From a62b2b1be2103d7de2fd66c7304b7473e369be3c Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 5 May 2021 14:25:10 +0100 Subject: Move item placement into item handlers (#5184) * Move item placement into item handlers + Add appropriate CanBeAt checks in cPlayer::PlaceBlocks, into which all placement handlers call. * Partly addresses #5157 * Fixes #4878 * Fixes #2919 * Fixes #4629 * Fixes #4239 * Fixes #4849 Co-authored-by: changyong guo Co-authored-by: Xotheus Co-authored-by: Krist Pregracke * Review fixes * Update APIDesc.lua * Rename Co-authored-by: changyong guo Co-authored-by: Xotheus Co-authored-by: Krist Pregracke --- Server/Plugins/APIDump/APIDesc.lua | 18 ++ src/BlockInfo.cpp | 11 + src/BlockInfo.h | 4 + src/Blocks/BlockAnvil.h | 22 -- src/Blocks/BlockBanner.h | 6 +- src/Blocks/BlockBed.cpp | 16 -- src/Blocks/BlockBed.h | 5 - src/Blocks/BlockBigFlower.h | 20 +- src/Blocks/BlockButton.h | 46 +---- src/Blocks/BlockCactus.h | 42 +--- src/Blocks/BlockCarpet.h | 22 +- src/Blocks/BlockChest.h | 182 ----------------- src/Blocks/BlockCocoaPod.h | 6 +- src/Blocks/BlockComparator.h | 6 +- src/Blocks/BlockCrops.h | 4 +- src/Blocks/BlockDeadBush.h | 8 +- src/Blocks/BlockDoor.h | 65 ++---- src/Blocks/BlockEndPortalFrame.h | 74 +------ src/Blocks/BlockFire.h | 10 +- src/Blocks/BlockFlower.h | 4 +- src/Blocks/BlockFluid.h | 2 +- src/Blocks/BlockHandler.cpp | 35 +--- src/Blocks/BlockHandler.h | 34 +--- src/Blocks/BlockHopper.h | 37 +--- src/Blocks/BlockLadder.h | 106 ++-------- src/Blocks/BlockLever.h | 53 +---- src/Blocks/BlockLilypad.h | 4 +- src/Blocks/BlockMushroom.h | 6 +- src/Blocks/BlockNetherWart.h | 4 +- src/Blocks/BlockPlanks.h | 18 -- src/Blocks/BlockPortal.h | 34 +--- src/Blocks/BlockPressurePlate.h | 9 +- src/Blocks/BlockQuartz.h | 60 ------ src/Blocks/BlockRail.h | 237 +++++++++------------- src/Blocks/BlockRedstone.h | 6 +- src/Blocks/BlockRedstoneRepeater.h | 6 +- src/Blocks/BlockSapling.h | 4 +- src/Blocks/BlockSideways.h | 60 +----- src/Blocks/BlockSignPost.h | 23 +-- src/Blocks/BlockSlab.h | 87 ++------ src/Blocks/BlockSnow.h | 61 ++---- src/Blocks/BlockStairs.h | 72 +------ src/Blocks/BlockStems.h | 4 +- src/Blocks/BlockSugarcane.h | 8 +- src/Blocks/BlockTallGrass.h | 8 +- src/Blocks/BlockTorch.h | 120 ++--------- src/Blocks/BlockTrapdoor.h | 68 ------- src/Blocks/BlockTripwireHook.h | 52 +---- src/Blocks/BlockVine.h | 115 +++++------ src/Blocks/BlockWallSign.h | 25 +-- src/Blocks/Mixins.h | 70 ++----- src/Blocks/WorldInterface.h | 4 +- src/ChunkMap.cpp | 6 +- src/ChunkMap.h | 2 +- src/ClientHandle.cpp | 74 +++---- src/Entities/Player.cpp | 45 +++-- src/Entities/Player.h | 6 +- src/Items/CMakeLists.txt | 24 +++ src/Items/ItemAnvil.h | 30 +++ src/Items/ItemBanner.h | 160 ++++++--------- src/Items/ItemBed.h | 60 ++++-- src/Items/ItemBigFlower.h | 36 ++-- src/Items/ItemBucket.h | 6 +- src/Items/ItemButton.h | 45 +++++ src/Items/ItemChest.h | 83 ++------ src/Items/ItemComparator.h | 14 +- src/Items/ItemDoor.h | 67 +++---- src/Items/ItemDropSpenser.h | 26 +++ src/Items/ItemDye.h | 2 +- src/Items/ItemEnchantingTable.h | 32 ++- src/Items/ItemEndPortalFrame.h | 26 +++ src/Items/ItemEnderchest.h | 26 +++ src/Items/ItemFenceGate.h | 26 +++ src/Items/ItemFurnace.h | 26 +++ src/Items/ItemGlazedTerracotta.h | 26 +++ src/Items/ItemHandler.cpp | 344 ++++++++++++++++++-------------- src/Items/ItemHandler.h | 54 +---- src/Items/ItemHopper.h | 40 ++++ src/Items/ItemJackOLantern.h | 27 +++ src/Items/ItemLadder.h | 77 +++++++ src/Items/ItemLeaves.h | 20 +- src/Items/ItemLever.h | 43 ++++ src/Items/ItemMobHead.h | 117 +++++------ src/Items/ItemNetherWart.h | 32 +-- src/Items/ItemObserver.h | 26 +++ src/Items/ItemPiston.h | 26 +++ src/Items/ItemPlanks.h | 25 +++ src/Items/ItemPumpkin.h | 70 +++---- src/Items/ItemQuartz.h | 60 ++++++ src/Items/ItemRail.h | 28 +++ src/Items/ItemRedstoneDust.h | 56 +----- src/Items/ItemRedstoneRepeater.h | 14 +- src/Items/ItemSapling.h | 28 +-- src/Items/ItemSeeds.h | 51 ++--- src/Items/ItemSideways.h | 53 +++++ src/Items/ItemSign.h | 89 ++++----- src/Items/ItemSlab.h | 134 ++++++------- src/Items/ItemSnow.h | 41 ++++ src/Items/ItemStairs.h | 47 +++++ src/Items/ItemTorch.h | 82 ++++++++ src/Items/ItemTrapdoor.h | 66 ++++++ src/Items/ItemTripwireHook.h | 43 ++++ src/Items/ItemVine.h | 44 ++++ src/Items/SimplePlaceableItemHandler.h | 9 +- src/World.cpp | 15 +- src/World.h | 12 +- tests/Generating/Stubs.cpp | 30 +-- tests/LuaThreadStress/Stubs.cpp | 30 +-- tests/SchematicFileSerializer/Stubs.cpp | 30 +-- 109 files changed, 2062 insertions(+), 2652 deletions(-) create mode 100644 src/Items/ItemAnvil.h create mode 100644 src/Items/ItemButton.h create mode 100644 src/Items/ItemDropSpenser.h create mode 100644 src/Items/ItemEndPortalFrame.h create mode 100644 src/Items/ItemEnderchest.h create mode 100644 src/Items/ItemFenceGate.h create mode 100644 src/Items/ItemFurnace.h create mode 100644 src/Items/ItemGlazedTerracotta.h create mode 100644 src/Items/ItemHopper.h create mode 100644 src/Items/ItemJackOLantern.h create mode 100644 src/Items/ItemLadder.h create mode 100644 src/Items/ItemLever.h create mode 100644 src/Items/ItemObserver.h create mode 100644 src/Items/ItemPiston.h create mode 100644 src/Items/ItemPlanks.h create mode 100644 src/Items/ItemQuartz.h create mode 100644 src/Items/ItemRail.h create mode 100644 src/Items/ItemSideways.h create mode 100644 src/Items/ItemSnow.h create mode 100644 src/Items/ItemStairs.h create mode 100644 src/Items/ItemTorch.h create mode 100644 src/Items/ItemTrapdoor.h create mode 100644 src/Items/ItemTripwireHook.h create mode 100644 src/Items/ItemVine.h diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua index 0e616a35c..ef3bc5ea0 100644 --- a/Server/Plugins/APIDump/APIDesc.lua +++ b/Server/Plugins/APIDump/APIDesc.lua @@ -222,6 +222,24 @@ return }, Notes = "Returns how much light the specified block type consumes.", }, + IsClickedThrough = + { + IsStatic = true, + Params = + { + { + Name = "BlockType", + Type = "number", + }, + }, + Returns = + { + { + Type = "boolean", + }, + }, + Notes = "Returns true if the specified block type is ignored by the client on left and right clicks, that is, treated as if it were air.", + }, IsOneHitDig = { IsStatic = true, diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp index f5bbe97e3..4981b2efe 100644 --- a/src/BlockInfo.cpp +++ b/src/BlockInfo.cpp @@ -715,6 +715,17 @@ bool cBlockInfo::FullyOccupiesVoxel(const BLOCKTYPE Block) +bool cBlockInfo::IsClickedThrough(const BLOCKTYPE a_Block) +{ + // TODO: Nether Fire too. + + return a_Block == E_BLOCK_FIRE; +} + + + + + bool cBlockInfo::IsOneHitDig(const BLOCKTYPE Block) { #ifdef __clang__ diff --git a/src/BlockInfo.h b/src/BlockInfo.h index fe5421690..a15868abe 100644 --- a/src/BlockInfo.h +++ b/src/BlockInfo.h @@ -24,6 +24,10 @@ public: /** Does this block fully occupy its voxel - is it a 'full' block? */ static bool FullyOccupiesVoxel(BLOCKTYPE Block); + /** Does the client pretend the block doesn't exist when clicking? + For example, digging a fire will hit the block below the fire, so fire is "clicked through". */ + static bool IsClickedThrough(BLOCKTYPE a_Block); + /** Is a block destroyed after a single hit? Warning: IsOneHitDig does not take into account enchantments / status effects / swim state / floating state and therefore may be incorrect. Only use to check if hardness is 0. diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h index 5746c936b..bc031216a 100644 --- a/src/Blocks/BlockAnvil.h +++ b/src/Blocks/BlockAnvil.h @@ -48,28 +48,6 @@ private: - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, a_BlockMeta)) - { - return false; - } - - a_BlockMeta = a_BlockMeta | static_cast(a_Player.GetEquippedItem().m_ItemDamage << 2); - return true; - } - - - - - virtual bool IsUseable() const override { return true; diff --git a/src/Blocks/BlockBanner.h b/src/Blocks/BlockBanner.h index cdcdfc179..e6a159bd4 100644 --- a/src/Blocks/BlockBanner.h +++ b/src/Blocks/BlockBanner.h @@ -29,14 +29,14 @@ public: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_RelPos.y < 1) + if (a_Position.y < 1) { return false; } - return cBlockInfo::IsSolid(a_Chunk.GetBlock(a_RelPos.addedY(-1))); + return cBlockInfo::IsSolid(a_Chunk.GetBlock(a_Position.addedY(-1))); } diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp index 37c57b6b3..728c9d2b7 100644 --- a/src/Blocks/BlockBed.cpp +++ b/src/Blocks/BlockBed.cpp @@ -9,7 +9,6 @@ #include "../World.h" #include "../BoundingBox.h" #include "../Mobs/Monster.h" -#include "../BlockEntities/BedEntity.h" @@ -158,21 +157,6 @@ bool cBlockBedHandler::OnUse( -void cBlockBedHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange) const -{ - a_Player.GetWorld()->DoWithBlockEntityAt(a_BlockChange.GetAbsolutePos(), [&a_Player](cBlockEntity & a_BlockEntity) - { - ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_BED); - - static_cast(a_BlockEntity).SetColor(a_Player.GetEquippedItem().m_ItemDamage); - return false; - }); -} - - - - - cItems cBlockBedHandler::ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const { // Drops handled by the block entity: diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h index 7da6740bd..d9f37b365 100644 --- a/src/Blocks/BlockBed.h +++ b/src/Blocks/BlockBed.h @@ -91,11 +91,6 @@ private: virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, const cItem * a_Tool) const override; - virtual void OnPlacedByPlayer( - cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, - const sSetBlock & a_BlockChange - ) const override; - diff --git a/src/Blocks/BlockBigFlower.h b/src/Blocks/BlockBigFlower.h index c21e411f3..6112329e9 100644 --- a/src/Blocks/BlockBigFlower.h +++ b/src/Blocks/BlockBigFlower.h @@ -20,14 +20,14 @@ public: private: - virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const override + virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const override { if (IsMetaTopPart(a_Meta)) { BLOCKTYPE BottomType; if ( - (a_Pos.y < 1) || - !a_ChunkInterface.GetBlockTypeMeta(a_Pos - Vector3i(0, 1, 0), BottomType, a_Meta) || + (a_Position.y < 1) || + !a_World.GetBlockTypeMeta(a_Position - Vector3i(0, 1, 0), BottomType, a_Meta) || (BottomType != E_BLOCK_BIG_FLOWER) ) { @@ -98,17 +98,13 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_RelPos.y <= 0) - { - return false; - } - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - a_Chunk.GetBlockTypeMeta(a_RelPos.addedY(-1), BlockType, BlockMeta); + // CanBeAt is also called on placement, so the top part can't check for the bottom part. + // Both parts can only that they're rooted in grass. - return IsBlockTypeOfDirt(BlockType) || ((BlockType == E_BLOCK_BIG_FLOWER) && !IsMetaTopPart(BlockMeta)); + const auto RootPosition = a_Position.addedY(IsMetaTopPart(a_Meta) ? -2 : -1); + return (RootPosition.y >= 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(RootPosition)); } diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h index 0c942cb49..896fd58d6 100644 --- a/src/Blocks/BlockButton.h +++ b/src/Blocks/BlockButton.h @@ -101,47 +101,6 @@ private: - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - a_BlockType = m_BlockType; - a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace); - return true; - } - - - - - - /** Converts the block face of the neighbor to which the button is attached, to the block meta for this button. */ - inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace) - { - switch (a_BlockFace) - { - case BLOCK_FACE_YP: return 0x5; - case BLOCK_FACE_ZM: return 0x4; - case BLOCK_FACE_ZP: return 0x3; - case BLOCK_FACE_XM: return 0x2; - case BLOCK_FACE_XP: return 0x1; - case BLOCK_FACE_YM: return 0x0; - case BLOCK_FACE_NONE: - { - break; - } - } - UNREACHABLE("Unsupported block face"); - } - - - - - /** Converts the block meta of this button into a block face of the neighbor to which the button is attached. */ inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta) { @@ -165,10 +124,9 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - auto Meta = a_Chunk.GetMeta(a_RelPos); - auto SupportRelPos = AddFaceDirection(a_RelPos, BlockMetaDataToBlockFace(Meta), true); + auto SupportRelPos = AddFaceDirection(a_Position, BlockMetaDataToBlockFace(a_Meta), true); if (!cChunkDef::IsValidHeight(SupportRelPos.y)) { return false; diff --git a/src/Blocks/BlockCactus.h b/src/Blocks/BlockCactus.h index 2e7cc7db2..23c4d3421 100644 --- a/src/Blocks/BlockCactus.h +++ b/src/Blocks/BlockCactus.h @@ -18,47 +18,13 @@ public: private: - /** Called before a cactus block is placed by a player, overrides cItemHandler::GetPlacementBlockTypeMeta(). - Calls CanBeAt function to determine if a cactus block can be placed on a given block. */ - bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if ( - a_Player.GetWorld()->DoWithChunkAt(a_PlacedBlockPos, - [this, a_PlacedBlockPos, &a_ChunkInterface](cChunk & a_Chunk) - { - auto RelPos = cChunkDef::AbsoluteToRelative(a_PlacedBlockPos); - return CanBeAt(a_ChunkInterface, RelPos, a_Chunk); - } - )) - { - a_BlockType = m_BlockType; - // Setting a_BlockMeta to meta copied from the lowest 4 bits of the player's equipped item's damage value. - NIBBLETYPE Meta = static_cast(a_Player.GetEquippedItem().m_ItemDamage); - a_BlockMeta = Meta & 0x0f; - return true; - } - - return false; - } - - - - - - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override - { - if (a_RelPos.y <= 0) + if (a_Position.y <= 0) { return false; } - BLOCKTYPE Surface = a_Chunk.GetBlock(a_RelPos.addedY(-1)); + BLOCKTYPE Surface = a_Chunk.GetBlock(a_Position.addedY(-1)); if ((Surface != E_BLOCK_SAND) && (Surface != E_BLOCK_CACTUS)) { // Cactus can only be placed on sand and itself @@ -78,7 +44,7 @@ private: BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; if ( - a_Chunk.UnboundedRelGetBlock(a_RelPos + Coords[i], BlockType, BlockMeta) && + a_Chunk.UnboundedRelGetBlock(a_Position + Coords[i], BlockType, BlockMeta) && ( cBlockInfo::IsSolid(BlockType) || (BlockType == E_BLOCK_LAVA) || diff --git a/src/Blocks/BlockCarpet.h b/src/Blocks/BlockCarpet.h index d4c172810..841e94b11 100644 --- a/src/Blocks/BlockCarpet.h +++ b/src/Blocks/BlockCarpet.h @@ -25,27 +25,9 @@ public: private: - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - a_BlockType = m_BlockType; - a_BlockMeta = a_Player.GetEquippedItem().m_ItemDamage & 0x0f; - return true; - } - - - - - - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override - { - return (a_RelPos.y > 0) && (a_Chunk.GetBlock(a_RelPos.addedY(-1)) != E_BLOCK_AIR); + return (a_Position.y > 0) && (a_Chunk.GetBlock(a_Position.addedY(-1)) != E_BLOCK_AIR); } diff --git a/src/Blocks/BlockChest.h b/src/Blocks/BlockChest.h index 88476c82d..119216d00 100644 --- a/src/Blocks/BlockChest.h +++ b/src/Blocks/BlockChest.h @@ -18,184 +18,6 @@ public: using Super::Super; - /** Translates player yaw when placing a chest into the chest block metadata. Valid for single chests only */ - static NIBBLETYPE PlayerYawToMetaData(double a_Yaw) - { - a_Yaw += 90 + 45; // So its not aligned with axis - - if (a_Yaw > 360.f) - { - a_Yaw -= 360.f; - } - if ((a_Yaw >= 0.f) && (a_Yaw < 90.f)) - { - return 0x04; - } - else if ((a_Yaw >= 180) && (a_Yaw < 270)) - { - return 0x05; - } - else if ((a_Yaw >= 90) && (a_Yaw < 180)) - { - return 0x02; - } - else - { - return 0x03; - } - } - -private: - - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - // Cannot place right next to double-chest: - if (!CanBeAt(a_ChunkInterface, a_PlacedBlockPos)) - { - // Yup, cannot form a triple-chest, refuse: - return false; - } - - // Try to read double-chest information: - cBlockArea Area; - if (!Area.Read(a_ChunkInterface, a_PlacedBlockPos - Vector3i(1, 0, 1), a_PlacedBlockPos + Vector3i(1, 0, 1))) - { - return false; - } - - // Get meta as if this was a single-chest: - if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, a_BlockMeta)) - { - return false; - } - - // Check if this forms a doublechest, if so, need to adjust the meta: - double yaw = a_Player.GetYaw(); - if ( - (Area.GetRelBlockType(0, 0, 1) == m_BlockType) || - (Area.GetRelBlockType(2, 0, 1) == m_BlockType) - ) - { - a_BlockMeta = ((yaw >= -90) && (yaw < 90)) ? 2 : 3; - return true; - } - if ( - (Area.GetRelBlockType(1, 0, 0) == m_BlockType) || - (Area.GetRelBlockType(1, 0, 2) == m_BlockType) - ) - { - a_BlockMeta = (yaw < 0) ? 4 : 5; - return true; - } - - - return true; - } - - - - - - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override - { - auto BlockPos = a_Chunk.RelativeToAbsolute(a_RelPos); - return CanBeAt(a_ChunkInterface, BlockPos); - } - - - - - - bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_BlockPos) const - { - cBlockArea Area; - if (!Area.Read(a_ChunkInterface, a_BlockPos - Vector3i(2, 0, 2), a_BlockPos + Vector3i(2, 0, 2))) - { - // Cannot read the surroundings, probably at the edge of loaded chunks. Disallow. - return false; - } - - int NumChestNeighbors = 0; - if (Area.GetRelBlockType(1, 0, 2) == m_BlockType) - { - if ( - (Area.GetRelBlockType(0, 0, 2) == m_BlockType) || - (Area.GetRelBlockType(1, 0, 1) == m_BlockType) || - (Area.GetRelBlockType(1, 0, 3) == m_BlockType) - ) - { - // Already a doublechest neighbor, disallow: - return false; - } - NumChestNeighbors += 1; - } - if (Area.GetRelBlockType(3, 0, 2) == m_BlockType) - { - if ( - (Area.GetRelBlockType(4, 0, 2) == m_BlockType) || - (Area.GetRelBlockType(3, 0, 1) == m_BlockType) || - (Area.GetRelBlockType(3, 0, 3) == m_BlockType) - ) - { - // Already a doublechest neighbor, disallow: - return false; - } - NumChestNeighbors += 1; - } - if (Area.GetRelBlockType(2, 0, 1) == m_BlockType) - { - if ( - (Area.GetRelBlockType(2, 0, 0) == m_BlockType) || - (Area.GetRelBlockType(1, 0, 1) == m_BlockType) || - (Area.GetRelBlockType(3, 0, 1) == m_BlockType) - ) - { - // Already a doublechest neighbor, disallow: - return false; - } - NumChestNeighbors += 1; - } - if (Area.GetRelBlockType(2, 0, 3) == m_BlockType) - { - if ( - (Area.GetRelBlockType(2, 0, 4) == m_BlockType) || - (Area.GetRelBlockType(1, 0, 3) == m_BlockType) || - (Area.GetRelBlockType(3, 0, 3) == m_BlockType) - ) - { - // Already a doublechest neighbor, disallow: - return false; - } - NumChestNeighbors += 1; - } - return (NumChestNeighbors < 2); - } - - - - - - /** If there's a chest in the a_Area in the specified coords, modifies its meta to a_NewMeta and returns true. */ - bool CheckAndAdjustNeighbor(cChunkInterface & a_ChunkInterface, const cBlockArea & a_Area, int a_RelX, int a_RelZ, NIBBLETYPE a_NewMeta) const - { - if (a_Area.GetRelBlockType(a_RelX, 0, a_RelZ) != m_BlockType) - { - return false; - } - a_ChunkInterface.SetBlockMeta(a_Area.GetOriginX() + a_RelX, a_Area.GetOriginY(), a_Area.GetOriginZ() + a_RelZ, a_NewMeta); - return true; - } - - - - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override { @@ -203,7 +25,3 @@ private: return 13; } } ; - - - - diff --git a/src/Blocks/BlockCocoaPod.h b/src/Blocks/BlockCocoaPod.h index 2df3a4408..e018388c5 100644 --- a/src/Blocks/BlockCocoaPod.h +++ b/src/Blocks/BlockCocoaPod.h @@ -36,11 +36,11 @@ public: private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { // Check that we're attached to a jungle log block: - eBlockFace BlockFace = MetaToBlockFace(a_Chunk.GetMeta(a_RelPos)); - auto LogPos = AddFaceDirection(a_RelPos, BlockFace, true); + eBlockFace BlockFace = MetaToBlockFace(a_Meta); + auto LogPos = AddFaceDirection(a_Position, BlockFace, true); BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; a_Chunk.UnboundedRelGetBlock(LogPos, BlockType, BlockMeta); diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h index 0eb03be86..e58b386c3 100644 --- a/src/Blocks/BlockComparator.h +++ b/src/Blocks/BlockComparator.h @@ -152,16 +152,16 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_RelPos.y <= 0) + if (a_Position.y <= 0) { return false; } BLOCKTYPE BelowBlock; NIBBLETYPE BelowBlockMeta; - a_Chunk.GetBlockTypeMeta(a_RelPos.addedY(-1), BelowBlock, BelowBlockMeta); + a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), BelowBlock, BelowBlockMeta); if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) { diff --git a/src/Blocks/BlockCrops.h b/src/Blocks/BlockCrops.h index 9a79f6ac0..90a5badc9 100644 --- a/src/Blocks/BlockCrops.h +++ b/src/Blocks/BlockCrops.h @@ -116,9 +116,9 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - return ((a_RelPos.y > 0) && (a_Chunk.GetBlock(a_RelPos.addedY(-1)) == E_BLOCK_FARMLAND)); + return (a_Position.y > 0) && (a_Chunk.GetBlock(a_Position.addedY(-1)) == E_BLOCK_FARMLAND); } diff --git a/src/Blocks/BlockDeadBush.h b/src/Blocks/BlockDeadBush.h index ba206baf8..080dd150c 100644 --- a/src/Blocks/BlockDeadBush.h +++ b/src/Blocks/BlockDeadBush.h @@ -18,7 +18,7 @@ public: private: - virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const override + virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, const NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const override { return true; } @@ -27,14 +27,14 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_RelPos.y <= 0) + if (a_Position.y <= 0) { return false; } - BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelPos.addedY(-1)); + BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_Position.addedY(-1)); switch (BelowBlock) { case E_BLOCK_CLAY: diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h index c6d4a7b9a..1b5c33d46 100644 --- a/src/Blocks/BlockDoor.h +++ b/src/Blocks/BlockDoor.h @@ -11,6 +11,8 @@ + + class cBlockDoorHandler final : public cYawRotator { @@ -43,25 +45,6 @@ public: } } - static bool CanReplaceBlock(BLOCKTYPE a_BlockType) - { - switch (a_BlockType) - { - case E_BLOCK_AIR: - case E_BLOCK_TALL_GRASS: - case E_BLOCK_WATER: - case E_BLOCK_STATIONARY_WATER: - case E_BLOCK_LAVA: - case E_BLOCK_STATIONARY_LAVA: - case E_BLOCK_SNOW: - case E_BLOCK_FIRE: - { - return true; - } - } - return false; - } - /** Returns a vector pointing one block in the direction the door is facing (where the outside is). */ inline static Vector3i GetRelativeDirectionToOutside(NIBBLETYPE a_BlockMeta) { @@ -167,38 +150,6 @@ private: virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) const override; virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) const override; virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) const override; - - - - - - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - // If clicking a bottom face, place the door one block lower: - auto PlacedPos = a_PlacedBlockPos; - if (a_ClickedBlockFace == BLOCK_FACE_BOTTOM) - { - PlacedPos.y--; - } - - if ( - !CanReplaceBlock(a_ChunkInterface.GetBlock(PlacedPos)) || - !CanReplaceBlock(a_ChunkInterface.GetBlock(PlacedPos.addedY(1))) - ) - { - return false; - } - - return Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, PlacedPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, a_BlockMeta); - } - virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) const override; @@ -237,9 +188,17 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - return ((a_RelPos.y > 0) && CanBeOn(a_Chunk.GetBlock(a_RelPos.addedY(-1)), a_Chunk.GetMeta(a_RelPos.addedY(-1)))); + // CanBeAt is also called on placement, so the top part can't check for the bottom part. + // Both parts can only that their base is a valid block. + + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + const auto BasePosition = a_Position.addedY(((a_Meta & 0x8) == 0x8) ? -2 : -1); + a_Chunk.GetBlockTypeMeta(BasePosition, BlockType, BlockMeta); + + return (BasePosition.y >= 0) && CanBeOn(BlockType, BlockMeta); } diff --git a/src/Blocks/BlockEndPortalFrame.h b/src/Blocks/BlockEndPortalFrame.h index 0b5e84da2..68e6e09fe 100644 --- a/src/Blocks/BlockEndPortalFrame.h +++ b/src/Blocks/BlockEndPortalFrame.h @@ -8,19 +8,19 @@ class cBlockEndPortalFrameHandler final : - public cMetaRotator { - using Super = cMetaRotator< + using Super = cYawRotator< cBlockHandler, 0x03, - E_META_END_PORTAL_FRAME_ZM, - E_META_END_PORTAL_FRAME_XP, E_META_END_PORTAL_FRAME_ZP, - E_META_END_PORTAL_FRAME_XM + E_META_END_PORTAL_FRAME_XM, + E_META_END_PORTAL_FRAME_ZM, + E_META_END_PORTAL_FRAME_XP >; public: @@ -29,54 +29,6 @@ public: private: - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - a_BlockType = m_BlockType; - a_BlockMeta = YawToMetaData(a_Player.GetYaw()); - return true; - } - - - - - - inline static NIBBLETYPE YawToMetaData(double a_Rotation) - { - a_Rotation += 90 + 45; // So its not aligned with axis - if (a_Rotation > 360) - { - a_Rotation -= 360; - } - - if ((a_Rotation >= 0) && (a_Rotation < 90)) - { - return E_META_END_PORTAL_FRAME_XM; - } - else if ((a_Rotation >= 180) && (a_Rotation < 270)) - { - return E_META_END_PORTAL_FRAME_XP; - } - else if ((a_Rotation >= 90) && (a_Rotation < 180)) - { - return E_META_END_PORTAL_FRAME_ZM; - } - else - { - return E_META_END_PORTAL_FRAME_ZP; - } - } - - - - - virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) const override { // E_META_END_PORTAL_FRAME_EYE is the bit which signifies the eye of ender is in it. @@ -237,16 +189,6 @@ private: - virtual bool IsClickedThrough(void) const override - { - // TODO: Colision - return true; - } - - - - - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockFire.h b/src/Blocks/BlockFire.h index 0f13db71b..a0f5e9a69 100644 --- a/src/Blocks/BlockFire.h +++ b/src/Blocks/BlockFire.h @@ -65,14 +65,6 @@ private: } - - - - virtual bool IsClickedThrough(void) const override - { - return true; - } - /** Traces along YP until it finds an obsidian block, returns Y difference or 0 if no portal, and -1 for border Takes the X, Y, and Z of the base block; with an optional MaxY for portal border finding */ static int FindObsidianCeiling(int X, int Y, int Z, cChunkInterface & a_ChunkInterface, int MaxY = 0) @@ -256,7 +248,7 @@ private: return (FoundFrameZP && FoundFrameZM); } - virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const override + virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, const NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const override { return true; } diff --git a/src/Blocks/BlockFlower.h b/src/Blocks/BlockFlower.h index 17cb529cb..023ba4a37 100644 --- a/src/Blocks/BlockFlower.h +++ b/src/Blocks/BlockFlower.h @@ -28,9 +28,9 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - return ((a_RelPos.y > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelPos.addedY(-1)))); + return (a_Position.y > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_Position.addedY(-1))); } diff --git a/src/Blocks/BlockFluid.h b/src/Blocks/BlockFluid.h index cdcf49299..b39476c1d 100644 --- a/src/Blocks/BlockFluid.h +++ b/src/Blocks/BlockFluid.h @@ -32,7 +32,7 @@ private: - virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const override + virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, const NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const override { return true; } diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 068ab998d..819289e14 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -456,24 +456,6 @@ namespace //////////////////////////////////////////////////////////////////////////////// // cBlockHandler: -bool cBlockHandler::GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - const Vector3i a_ClickedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta -) const -{ - // By default, all blocks can be placed and the meta is copied over from the item's damage value: - a_BlockType = m_BlockType; - a_BlockMeta = static_cast(a_Player.GetEquippedItem().m_ItemDamage & 0x0f); - return true; -} - - - - - void cBlockHandler::OnUpdate( cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, @@ -490,7 +472,7 @@ void cBlockHandler::OnUpdate( void cBlockHandler::OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) const { - if (a_ChunkInterface.DoWithChunkAt(a_BlockPos, [&](cChunk & a_Chunk) { return CanBeAt(a_ChunkInterface, cChunkDef::AbsoluteToRelative(a_BlockPos), a_Chunk); })) + if (a_ChunkInterface.DoWithChunkAt(a_BlockPos, [&](cChunk & a_Chunk) { return CanBeAt(a_Chunk, cChunkDef::AbsoluteToRelative(a_BlockPos), a_Chunk.GetMeta(cChunkDef::AbsoluteToRelative(a_BlockPos))); })) { return; } @@ -528,7 +510,7 @@ cItems cBlockHandler::ConvertToPickups(NIBBLETYPE a_BlockMeta, const cItem * con -bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const +bool cBlockHandler::CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const { return true; } @@ -546,18 +528,9 @@ bool cBlockHandler::IsUseable() const -bool cBlockHandler::IsClickedThrough(void) const -{ - return false; -} - - - - - -bool cBlockHandler::DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const +bool cBlockHandler::DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, const NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const { - return (m_BlockType == E_BLOCK_AIR); + return m_BlockType == E_BLOCK_AIR; } diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h index da067fd63..c0e9d3a3d 100644 --- a/src/Blocks/BlockHandler.h +++ b/src/Blocks/BlockHandler.h @@ -14,6 +14,7 @@ class cPlayer; class cChunk; class cBlockPluginInterface; class cChunkInterface; +class cWorld; class cWorldInterface; class cItems; @@ -45,22 +46,6 @@ public: blocktype of the minus-X neighbor, the positive-X neighbor, etc. */ virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) const; - /** Called before a block is placed into a world by player, by cItemHandler::GetPlacementBlockTypeMeta(). - The handler should return true to allow placement, false to refuse. - a_PlacedBlockPos is the coords of the block being placed - a_ClickedBlockFace is the face of the neighbor block clicked by the client to place this block. - a_CursorPos is the position of the cursor within the neighbor's face - The descendant handler should set a_BlockType and a_BlockMeta to correct values for the newly placed block. - The default handler uses the stored block type and meta copied from the lowest 4 bits of the player's equipped item's damage value. */ - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const; - /** Called by cWorld::SetBlock() after the block has been set */ virtual void OnPlaced( cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, @@ -68,11 +53,6 @@ public: BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) const {} - /** Called by cPlayer::PlaceBlocks() for each block after it has been set to the world. Called after OnPlaced(). */ - virtual void OnPlacedByPlayer( - cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange - ) const {} - /** Called after a block gets broken (replaced with air), by natural means. The block is already dug up in the world, the original block type and meta is passed in a_OldBlockType and a_OldBlockMeta. By default notifies all direct neighbors via their OnNeighborChanged() callbacks. @@ -142,11 +122,7 @@ public: virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, const cItem * a_Tool = nullptr) const; /** Checks if the block can stay at the specified relative coords in the chunk */ - virtual bool CanBeAt( - cChunkInterface & a_ChunkInterface, - const Vector3i a_RelPos, - const cChunk & a_Chunk - ) const; + virtual bool CanBeAt(const cChunk & a_Chunk, Vector3i a_Position, NIBBLETYPE a_Meta) const; /** Checks whether the block has an effect on growing the plant */ virtual bool CanSustainPlant(BLOCKTYPE a_Plant) const { return false; } @@ -155,16 +131,12 @@ public: If it returns true, OnUse() is called */ virtual bool IsUseable(void) const; - /** Indicates whether the client will click through this block. - For example digging a fire will hit the block below the fire so fire is clicked through. */ - virtual bool IsClickedThrough(void) const; - /** Checks if the player can build "inside" this block. For example blocks placed "on" snow will be placed at the same position. So: Snow ignores Build collision @param a_Pos Position of the block @param a_Player Player trying to build on the block @param a_Meta Meta value of the block currently at a_Pos */ - virtual bool DoesIgnoreBuildCollision(cChunkInterface & ChunkInterface, const Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const; + virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, Vector3i a_Position, NIBBLETYPE a_Meta, eBlockFace a_ClickedBlockFace, bool a_ClickedDirectly) const; /** Tests if a_RelPosition is inside the block, where a_RelPosition is relative to the origin of the block. Coords in a_RelPosition are guaranteed to be in the [0..1] range. */ diff --git a/src/Blocks/BlockHopper.h b/src/Blocks/BlockHopper.h index 915a8d8d5..930f1e0bc 100644 --- a/src/Blocks/BlockHopper.h +++ b/src/Blocks/BlockHopper.h @@ -8,9 +8,9 @@ class cBlockHopperHandler final : - public cPitchYawRotator> + public cClearMetaOnDrop> { - using Super = cPitchYawRotator>; + using Super = cClearMetaOnDrop>; public: @@ -18,42 +18,9 @@ public: private: - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - a_BlockType = m_BlockType; - - // Convert the blockface into meta: - switch (a_ClickedBlockFace) - { - case BLOCK_FACE_BOTTOM: a_BlockMeta = E_META_HOPPER_FACING_YM; break; - case BLOCK_FACE_TOP: a_BlockMeta = E_META_HOPPER_FACING_YM; break; - case BLOCK_FACE_EAST: a_BlockMeta = E_META_HOPPER_FACING_XM; break; - case BLOCK_FACE_NORTH: a_BlockMeta = E_META_HOPPER_FACING_ZP; break; - case BLOCK_FACE_SOUTH: a_BlockMeta = E_META_HOPPER_FACING_ZM; break; - case BLOCK_FACE_WEST: a_BlockMeta = E_META_HOPPER_FACING_XP; break; - case BLOCK_FACE_NONE: a_BlockMeta = E_META_HOPPER_UNATTACHED; break; - } - return true; - } - - - - - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override { UNUSED(a_Meta); return 11; } } ; - - - - diff --git a/src/Blocks/BlockLadder.h b/src/Blocks/BlockLadder.h index b4e8294b6..06ef2b01c 100644 --- a/src/Blocks/BlockLadder.h +++ b/src/Blocks/BlockLadder.h @@ -2,6 +2,7 @@ #pragma once #include "BlockHandler.h" +#include "BlockInfo.h" #include "Mixins.h" @@ -17,58 +18,23 @@ public: using Super::Super; -private: - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override + /** Returns true if the ladder will be supported by the block through the given blockface. */ + static bool CanBePlacedOn(const BLOCKTYPE a_BlockType, const eBlockFace a_BlockFace) { - // Try finding a suitable neighbor block face for the ladder; start with the given one. - if (!LadderCanBePlacedAt(a_ChunkInterface, a_PlacedBlockPos, a_ClickedBlockFace)) + if ( + (a_BlockFace == BLOCK_FACE_NONE) || + (a_BlockFace == BLOCK_FACE_BOTTOM) || + (a_BlockFace == BLOCK_FACE_TOP) + ) { - a_ClickedBlockFace = FindSuitableBlockFace(a_ChunkInterface, a_PlacedBlockPos); - if (a_ClickedBlockFace == BLOCK_FACE_NONE) - { - return false; - } + return false; } - a_BlockType = m_BlockType; - a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace); - return true; - } - - - - - - /** Converts the block face of the neighbor to which the ladder is attached to the ladder block's meta. */ - static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_NeighborBlockFace) - { - switch (a_NeighborBlockFace) - { - case BLOCK_FACE_ZM: return 0x2; - case BLOCK_FACE_ZP: return 0x3; - case BLOCK_FACE_XM: return 0x4; - case BLOCK_FACE_XP: return 0x5; - case BLOCK_FACE_NONE: - case BLOCK_FACE_YM: - case BLOCK_FACE_YP: - { - return 0x2; - } - } - UNREACHABLE("Unsupported neighbor block face"); + return cBlockInfo::IsSolid(a_BlockType); } - - - +private: /** Converts the ladder block's meta to the block face of the neighbor to which the ladder is attached. */ static eBlockFace MetaDataToBlockFace(NIBBLETYPE a_MetaData) @@ -87,51 +53,13 @@ private: - /** Finds a suitable block face value for the Ladder. - The returned value is the block face of the neighbor of the specified block to which a ladder at a_LadderPos can be attached. - Returns BLOCK_FACE_NONE if no valid location is found */ - static eBlockFace FindSuitableBlockFace(cChunkInterface & a_ChunkInterface, const Vector3i a_LadderPos) - { - for (int FaceInt = BLOCK_FACE_ZM; FaceInt <= BLOCK_FACE_XP; FaceInt++) - { - eBlockFace Face = static_cast(FaceInt); - if (LadderCanBePlacedAt(a_ChunkInterface, a_LadderPos, Face)) - { - return Face; - } - } - return BLOCK_FACE_NONE; - } - - - - - - /** Returns true if the ladder in the specified position will be supported by its neghbor through the specified neighbor's blockface. */ - static bool LadderCanBePlacedAt(cChunkInterface & a_ChunkInterface, const Vector3i a_LadderPos, eBlockFace a_NeighborBlockFace) - { - if ( - (a_NeighborBlockFace == BLOCK_FACE_NONE) || - (a_NeighborBlockFace == BLOCK_FACE_BOTTOM) || - (a_NeighborBlockFace == BLOCK_FACE_TOP) - ) - { - return false; - } - - auto NeighborPos = AddFaceDirection(a_LadderPos, a_NeighborBlockFace, true); - return cBlockInfo::IsSolid(a_ChunkInterface.GetBlock(NeighborPos)); - } - - - - - - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - auto NeighborBlockFace = MetaDataToBlockFace(a_Chunk.GetMeta(a_RelPos)); - auto LadderAbsPos = a_Chunk.RelativeToAbsolute(a_RelPos); - return LadderCanBePlacedAt(a_ChunkInterface, LadderAbsPos, NeighborBlockFace); + auto Face = MetaDataToBlockFace(a_Meta); + auto NeighborRelPos = AddFaceDirection(a_Position, Face, true); + BLOCKTYPE NeighborBlockType; + a_Chunk.UnboundedRelGetBlockType(NeighborRelPos, NeighborBlockType); + return CanBePlacedOn(NeighborBlockType, Face); } diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h index ee5e99b9c..ddb459fbe 100644 --- a/src/Blocks/BlockLever.h +++ b/src/Blocks/BlockLever.h @@ -64,45 +64,6 @@ private: - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - a_BlockType = m_BlockType; - a_BlockMeta = LeverDirectionToMetaData(a_ClickedBlockFace); - return true; - } - - - - - - /** Converts the block face of the neighbor to which the lever is attached to the lever block's meta. */ - inline static NIBBLETYPE LeverDirectionToMetaData(eBlockFace a_Dir) - { - // Determine lever direction: - switch (a_Dir) - { - case BLOCK_FACE_YP: return 0x6; - case BLOCK_FACE_XP: return 0x1; - case BLOCK_FACE_XM: return 0x2; - case BLOCK_FACE_ZP: return 0x3; - case BLOCK_FACE_ZM: return 0x4; - case BLOCK_FACE_YM: return 0x0; - case BLOCK_FACE_NONE: return 0x6; - } - UNREACHABLE("Unsupported block face"); - } - - - - - /** Converts the leve block's meta to the block face of the neighbor to which the lever is attached. */ inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta) { @@ -128,18 +89,18 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { // Find the type of block the lever is attached to: - auto Meta = a_Chunk.GetMeta(a_RelPos); - auto NeighborFace = BlockMetaDataToBlockFace(Meta); - auto NeighborPos = AddFaceDirection(a_RelPos, NeighborFace, true); + auto NeighborFace = BlockMetaDataToBlockFace(a_Meta); + auto NeighborPos = AddFaceDirection(a_Position, NeighborFace, true); if (!cChunkDef::IsValidHeight(NeighborPos.y)) { return false; } BLOCKTYPE NeighborBlockType; - if (!a_Chunk.UnboundedRelGetBlock(NeighborPos, NeighborBlockType, Meta)) + NIBBLETYPE NeighborMeta; + if (!a_Chunk.UnboundedRelGetBlock(NeighborPos, NeighborBlockType, NeighborMeta)) { return false; } @@ -152,8 +113,8 @@ private: else if (cBlockSlabHandler::IsAnySlabType(NeighborBlockType)) { return ( - (((Meta & 0x08) == 0x08) && (NeighborFace == BLOCK_FACE_TOP)) || - (((Meta & 0x08) == 0) && (NeighborFace == BLOCK_FACE_BOTTOM)) + (((NeighborMeta & 0x08) == 0x08) && (NeighborFace == BLOCK_FACE_TOP)) || + (((NeighborMeta & 0x08) == 0) && (NeighborFace == BLOCK_FACE_BOTTOM)) ); } diff --git a/src/Blocks/BlockLilypad.h b/src/Blocks/BlockLilypad.h index 165e2d310..6d25a0e2d 100644 --- a/src/Blocks/BlockLilypad.h +++ b/src/Blocks/BlockLilypad.h @@ -28,9 +28,9 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - auto UnderPos = a_RelPos.addedY(-1); + auto UnderPos = a_Position.addedY(-1); if (!cChunkDef::IsValidHeight(UnderPos.y)) { return false; diff --git a/src/Blocks/BlockMushroom.h b/src/Blocks/BlockMushroom.h index bad4fc247..bed16c557 100644 --- a/src/Blocks/BlockMushroom.h +++ b/src/Blocks/BlockMushroom.h @@ -21,16 +21,16 @@ private: // TODO: Add Mushroom Spread - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_RelPos.y <= 0) + if (a_Position.y <= 0) { return false; } // TODO: Cannot be at too much daylight - switch (a_Chunk.GetBlock(a_RelPos.addedY(-1))) + switch (a_Chunk.GetBlock(a_Position.addedY(-1))) { case E_BLOCK_GLASS: case E_BLOCK_CACTUS: diff --git a/src/Blocks/BlockNetherWart.h b/src/Blocks/BlockNetherWart.h index 4afdaffa2..43081d511 100644 --- a/src/Blocks/BlockNetherWart.h +++ b/src/Blocks/BlockNetherWart.h @@ -57,10 +57,10 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { // Needs to be placed on top of a Soulsand block: - return ((a_RelPos.y > 0) && (a_Chunk.GetBlock(a_RelPos.addedY(-1)) == E_BLOCK_SOULSAND)); + return (a_Position.y > 0) && (a_Chunk.GetBlock(a_Position.addedY(-1)) == E_BLOCK_SOULSAND); } diff --git a/src/Blocks/BlockPlanks.h b/src/Blocks/BlockPlanks.h index f095f9ea3..d6e79b3c0 100644 --- a/src/Blocks/BlockPlanks.h +++ b/src/Blocks/BlockPlanks.h @@ -18,24 +18,6 @@ public: private: - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - a_BlockType = m_BlockType; - a_BlockMeta = static_cast(a_Player.GetEquippedItem().m_ItemDamage); - return true; - } - - - - - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override { switch (a_Meta) diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h index cc7fa3a1f..05daa9337 100644 --- a/src/Blocks/BlockPortal.h +++ b/src/Blocks/BlockPortal.h @@ -18,28 +18,6 @@ public: private: - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - // We set meta to zero so Cuberite doesn't stop a Creative-mode player from building custom portal shapes - // CanBeAt doesn't do anything if meta is zero - // We set to zero because the client sends meta = 1 or 2 to the server (it calculates rotation itself) - - a_BlockType = m_BlockType; - a_BlockMeta = 0; - return true; - } - - - - - virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override { // No pickups @@ -71,14 +49,14 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if ((a_RelPos.y <= 0) || (a_RelPos.y >= cChunkDef::Height - 1)) + if ((a_Position.y <= 0) || (a_Position.y >= cChunkDef::Height - 1)) { - return false; // In case someone places a portal with meta 1 or 2 at boundaries, and server tries to get invalid coords at Y - 1 or Y + 1 + return false; // In case someone places a portal with meta 1 or 2 at boundaries, and server tries to get invalid coords at Y - 1 or Y + 1. } - switch (a_Chunk.GetMeta(a_RelPos)) + switch (a_Meta) { case 0x1: { @@ -95,7 +73,7 @@ private: for (const auto & Direction : PortalCheck) { BLOCKTYPE Block; - a_Chunk.UnboundedRelGetBlockType(a_RelPos + Direction, Block); + a_Chunk.UnboundedRelGetBlockType(a_Position + Direction, Block); if ((Block != E_BLOCK_NETHER_PORTAL) && (Block != E_BLOCK_OBSIDIAN)) { return false; @@ -118,7 +96,7 @@ private: for (const auto & Direction : PortalCheck) { BLOCKTYPE Block; - a_Chunk.UnboundedRelGetBlockType(a_RelPos + Direction, Block); + a_Chunk.UnboundedRelGetBlockType(a_Position + Direction, Block); if ((Block != E_BLOCK_NETHER_PORTAL) && (Block != E_BLOCK_OBSIDIAN)) { return false; diff --git a/src/Blocks/BlockPressurePlate.h b/src/Blocks/BlockPressurePlate.h index c9a72a751..d2f05b2e7 100644 --- a/src/Blocks/BlockPressurePlate.h +++ b/src/Blocks/BlockPressurePlate.h @@ -17,15 +17,16 @@ public: private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_RelPos.y <= 1) + if (a_Position.y <= 0) { return false; } // TODO: check if the block is upside-down slab or upside-down stairs - auto Block = a_Chunk.GetBlock(a_RelPos.addedY(-1)); + + const auto Block = a_Chunk.GetBlock(a_Position.addedY(-1)); switch (Block) { case E_BLOCK_ACACIA_FENCE: @@ -41,7 +42,7 @@ private: } default: { - return (!cBlockInfo::IsTransparent(Block)); + return !cBlockInfo::IsTransparent(Block); } } } diff --git a/src/Blocks/BlockQuartz.h b/src/Blocks/BlockQuartz.h index d05c05ba3..bc10985df 100644 --- a/src/Blocks/BlockQuartz.h +++ b/src/Blocks/BlockQuartz.h @@ -18,66 +18,6 @@ public: private: - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - a_BlockType = m_BlockType; - auto Meta = static_cast(a_Player.GetEquippedItem().m_ItemDamage); - - // Pillar block needs additional direction in the metadata: - if (Meta != E_META_QUARTZ_PILLAR) - { - a_BlockMeta = Meta; - return true; - } - a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace); - return true; - } - - - - - - /** Converts the block face of the pillar block's "base" to the block's metadata. */ - inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace) - { - switch (a_BlockFace) - { - case BLOCK_FACE_YM: - case BLOCK_FACE_YP: - { - return E_META_QUARTZ_PILLAR; // Top or bottom - } - - case BLOCK_FACE_ZP: - case BLOCK_FACE_ZM: - { - return 0x4; // North or south - } - - case BLOCK_FACE_XP: - case BLOCK_FACE_XM: - { - return 0x3; // East or west - } - - default: - { - return E_META_QUARTZ_PILLAR; - } - } - } - - - - - virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override { UNUSED(a_Meta); diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h index 7c147d48a..d822e728f 100644 --- a/src/Blocks/BlockRail.h +++ b/src/Blocks/BlockRail.h @@ -25,141 +25,8 @@ public: using Super::Super; -private: - - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - a_BlockType = m_BlockType; - a_BlockMeta = FindMeta(a_ChunkInterface, a_PlacedBlockPos); - return a_Player.GetWorld()->DoWithChunkAt(a_PlacedBlockPos, - [this, a_PlacedBlockPos, &a_ChunkInterface](cChunk & a_Chunk) - { - auto RelPos = cChunkDef::AbsoluteToRelative(a_PlacedBlockPos); - return CanBeAt(a_ChunkInterface, RelPos, a_Chunk); - } - ); - } - - - - - - virtual void OnPlaced( - cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, - Vector3i a_BlockPos, - BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta - ) const override - { - Super::OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockPos, a_BlockType, a_BlockMeta); - - // Alert diagonal rails: - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, 1, 0), BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, 1, 0), BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, 1), BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, -1), BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, -1, 0), BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, -1, 0), BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, 1), BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, -1), BLOCK_FACE_NONE); - } - - - - - - virtual void OnBroken( - cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, - Vector3i a_BlockPos, - BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta, - const cEntity * a_Digger - ) const override - { - Super::OnBroken(a_ChunkInterface, a_WorldInterface, a_BlockPos, a_OldBlockType, a_OldBlockMeta, a_Digger); - - // Alert diagonal rails: - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, 1, 0), BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, 1, 0), BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, 1), BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, -1), BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, -1, 0), BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, -1, 0), BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, 1), BLOCK_FACE_NONE); - NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, -1), BLOCK_FACE_NONE); - } - - - - - virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) const override - { - const auto Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos); - const auto NewMeta = FindMeta(a_ChunkInterface, a_BlockPos); - if ((Meta != NewMeta) && IsUnstable(a_ChunkInterface, a_BlockPos)) - { - a_ChunkInterface.FastSetBlock(a_BlockPos, m_BlockType, (m_BlockType == E_BLOCK_RAIL) ? NewMeta : NewMeta | (Meta & 0x08)); - } - - Super::OnNeighborChanged(a_ChunkInterface, a_BlockPos, a_WhichNeighbor); - } - - - - - - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override - { - if (a_RelPos.y <= 0) - { - return false; - } - if (!cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(a_RelPos.addedY(-1)))) - { - return false; - } - - NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelPos); - switch (Meta) - { - case E_META_RAIL_ASCEND_XP: - case E_META_RAIL_ASCEND_XM: - case E_META_RAIL_ASCEND_ZM: - case E_META_RAIL_ASCEND_ZP: - { - // Mapping between the meta and the neighbors that need checking - Meta -= E_META_RAIL_ASCEND_XP; // Base index at zero - static const Vector3i Coords[] = - { - { 1, 0, 0}, // east, XP - {-1, 0, 0}, // west, XM - { 0, 0, -1}, // north, ZM - { 0, 0, 1}, // south, ZP - } ; - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - if (!a_Chunk.UnboundedRelGetBlock(a_RelPos + Coords[Meta], BlockType, BlockMeta)) - { - // Too close to the edge, cannot simulate - return true; - } - return cBlockInfo::FullyOccupiesVoxel(BlockType); - } - } - return true; - } - - - - - - NIBBLETYPE FindMeta(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos) const + static NIBBLETYPE FindMeta(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, BLOCKTYPE a_RailType) { NIBBLETYPE Meta = 0; char RailsCnt = 0; @@ -234,19 +101,21 @@ private: } if (RailsCnt > 1) { - if (Neighbors[3] && Neighbors[0] && CanThisRailCurve()) + const bool CanCurve = a_RailType == E_BLOCK_RAIL; + + if (Neighbors[3] && Neighbors[0] && CanCurve) { return E_META_RAIL_CURVED_ZP_XP; } - else if (Neighbors[3] && Neighbors[1] && CanThisRailCurve()) + else if (Neighbors[3] && Neighbors[1] && CanCurve) { return E_META_RAIL_CURVED_ZP_XM; } - else if (Neighbors[2] && Neighbors[0] && CanThisRailCurve()) + else if (Neighbors[2] && Neighbors[0] && CanCurve) { return E_META_RAIL_CURVED_ZM_XP; } - else if (Neighbors[2] && Neighbors[1] && CanThisRailCurve()) + else if (Neighbors[2] && Neighbors[1] && CanCurve) { return E_META_RAIL_CURVED_ZM_XM; } @@ -275,7 +144,7 @@ private: return E_META_RAIL_ZM_ZP; } - if (CanThisRailCurve()) + if (CanCurve) { ASSERT(!"Weird neighbor count"); } @@ -283,10 +152,42 @@ private: return Meta; } +private: - bool CanThisRailCurve(void) const + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, NIBBLETYPE a_Meta) const override { - return m_BlockType == E_BLOCK_RAIL; + if ((a_Position.y <= 0) || !cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(a_Position.addedY(-1)))) + { + return false; + } + + switch (a_Meta) + { + case E_META_RAIL_ASCEND_XP: + case E_META_RAIL_ASCEND_XM: + case E_META_RAIL_ASCEND_ZM: + case E_META_RAIL_ASCEND_ZP: + { + // Mapping between the meta and the neighbors that need checking + a_Meta -= E_META_RAIL_ASCEND_XP; // Base index at zero + static const Vector3i Coords[] = + { + { 1, 0, 0}, // east, XP + {-1, 0, 0}, // west, XM + { 0, 0, -1}, // north, ZM + { 0, 0, 1}, // south, ZP + } ; + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + if (!a_Chunk.UnboundedRelGetBlock(a_Position + Coords[a_Meta], BlockType, BlockMeta)) + { + // Too close to the edge, cannot simulate + return true; + } + return cBlockInfo::FullyOccupiesVoxel(BlockType); + } + } + return true; } @@ -521,6 +422,60 @@ private: } + virtual void OnBroken( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta, + const cEntity * a_Digger + ) const override + { + Super::OnBroken(a_ChunkInterface, a_WorldInterface, a_BlockPos, a_OldBlockType, a_OldBlockMeta, a_Digger); + + // Alert diagonal rails: + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, 1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, 1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, 1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, -1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, -1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, -1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, 1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, -1), BLOCK_FACE_NONE); + } + + + virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) const override + { + const auto Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos); + const auto NewMeta = FindMeta(a_ChunkInterface, a_BlockPos, m_BlockType); + if ((Meta != NewMeta) && IsUnstable(a_ChunkInterface, a_BlockPos)) + { + a_ChunkInterface.FastSetBlock(a_BlockPos, m_BlockType, (m_BlockType == E_BLOCK_RAIL) ? NewMeta : NewMeta | (Meta & 0x08)); + } + + Super::OnNeighborChanged(a_ChunkInterface, a_BlockPos, a_WhichNeighbor); + } + + + virtual void OnPlaced( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, + Vector3i a_BlockPos, + BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta + ) const override + { + Super::OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockPos, a_BlockType, a_BlockMeta); + + // Alert diagonal rails: + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, 1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, 1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, 1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, -1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, -1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, -1, 0), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, 1), BLOCK_FACE_NONE); + NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, -1), BLOCK_FACE_NONE); + } + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) const override { // Bit 0x08 is a flag when a_Meta is in the range 0x00--0x05 and 0x0A--0x0F. diff --git a/src/Blocks/BlockRedstone.h b/src/Blocks/BlockRedstone.h index 8a7e35aa1..d77ff151a 100644 --- a/src/Blocks/BlockRedstone.h +++ b/src/Blocks/BlockRedstone.h @@ -19,16 +19,16 @@ public: private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_RelPos.y <= 0) + if (a_Position.y <= 0) { return false; } BLOCKTYPE BelowBlock; NIBBLETYPE BelowBlockMeta; - a_Chunk.GetBlockTypeMeta(a_RelPos.addedY(-1), BelowBlock, BelowBlockMeta); + a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), BelowBlock, BelowBlockMeta); if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) { diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h index 97b16f174..4b9650e90 100644 --- a/src/Blocks/BlockRedstoneRepeater.h +++ b/src/Blocks/BlockRedstoneRepeater.h @@ -105,16 +105,16 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_RelPos.y <= 0) + if (a_Position.y <= 0) { return false; } BLOCKTYPE BelowBlock; NIBBLETYPE BelowBlockMeta; - a_Chunk.GetBlockTypeMeta(a_RelPos.addedY(-1), BelowBlock, BelowBlockMeta); + a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), BelowBlock, BelowBlockMeta); if (cBlockInfo::FullyOccupiesVoxel(BelowBlock)) { diff --git a/src/Blocks/BlockSapling.h b/src/Blocks/BlockSapling.h index ab3f66edc..d32b9b449 100644 --- a/src/Blocks/BlockSapling.h +++ b/src/Blocks/BlockSapling.h @@ -29,9 +29,9 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - return (a_RelPos.y > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelPos.addedY(-1))); + return (a_Position.y > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_Position.addedY(-1))); } diff --git a/src/Blocks/BlockSideways.h b/src/Blocks/BlockSideways.h index 17751a565..f2c4ce4e6 100644 --- a/src/Blocks/BlockSideways.h +++ b/src/Blocks/BlockSideways.h @@ -8,7 +8,6 @@ /** Handler for blocks that have 3 orientations (hay bale, log), specified by the upper 2 bits in meta. -Handles setting the correct orientation on placement. Additionally supports the metadata specifying block sub-type in its lower 2 bits. */ class cBlockSidewaysHandler final : public cBlockHandler @@ -21,66 +20,9 @@ public: private: - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - a_BlockType = m_BlockType; - NIBBLETYPE Meta = static_cast(a_Player.GetEquippedItem().m_ItemDamage); - a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace, Meta); - return true; - } - - - - - virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override { - // Reset the orientation part of meta, keep the sub-type part of meta + // Reset the orientation part of meta, keep the sub-type part of meta: return cItem(m_BlockType, 1, a_BlockMeta & 0x03); } - - - - - - inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace, NIBBLETYPE a_Meta) - { - switch (a_BlockFace) - { - case BLOCK_FACE_YM: - case BLOCK_FACE_YP: - { - return a_Meta; // Top or bottom, just return original - } - - case BLOCK_FACE_ZP: - case BLOCK_FACE_ZM: - { - return a_Meta | 0x8; // North or south - } - - case BLOCK_FACE_XP: - case BLOCK_FACE_XM: - { - return a_Meta | 0x4; // East or west - } - - case BLOCK_FACE_NONE: - { - break; - } - } - UNREACHABLE("Unsupported block face"); - } } ; - - - - diff --git a/src/Blocks/BlockSignPost.h b/src/Blocks/BlockSignPost.h index 8d31ae7fa..b96498cbd 100644 --- a/src/Blocks/BlockSignPost.h +++ b/src/Blocks/BlockSignPost.h @@ -17,20 +17,6 @@ public: using Super::Super; - /** Converts the (player) rotation to placed-signpost block meta. */ - static NIBBLETYPE RotationToMetaData(double a_Rotation) - { - a_Rotation += 180 + (180 / 16); // So it's not aligned with axis - if (a_Rotation > 360) - { - a_Rotation -= 360; - } - - a_Rotation = (a_Rotation / 360) * 16; - - return (static_cast(a_Rotation)) % 16; - } - private: virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override @@ -42,14 +28,15 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_RelPos.y <= 0) + if (a_Position.y <= 0) { return false; } - BLOCKTYPE Type = a_Chunk.GetBlock(a_RelPos.addedY(-1)); - return ((Type == E_BLOCK_SIGN_POST) || (Type == E_BLOCK_WALLSIGN) || cBlockInfo::IsSolid(Type)); + + BLOCKTYPE Type = a_Chunk.GetBlock(a_Position.addedY(-1)); + return (Type == E_BLOCK_SIGN_POST) || (Type == E_BLOCK_WALLSIGN) || cBlockInfo::IsSolid(Type); } diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h index 98f327b5b..566c88c71 100644 --- a/src/Blocks/BlockSlab.h +++ b/src/Blocks/BlockSlab.h @@ -46,64 +46,25 @@ private: } - - - - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override + virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, const NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const override { - a_BlockType = m_BlockType; - NIBBLETYPE Meta = static_cast(a_Player.GetEquippedItem().m_ItemDamage); - - // Set the correct metadata based on player equipped item (i.e. a_BlockMeta not initialised yet) - switch (a_ClickedBlockFace) + /* Double slab combining uses build collision checks to replace single slabs with double slabs in the right conditions. + For us to be replaced, the player must be: + 1. Placing the same slab material. + 2. Placing the same slab sub-kind (and existing slab is single). */ + if ((m_BlockType != a_HeldItem.m_ItemType) || ((a_Meta & 0x07) != a_HeldItem.m_ItemDamage)) { - case BLOCK_FACE_TOP: - { - // Bottom half slab block - a_BlockMeta = Meta & 0x07; - break; - } - case BLOCK_FACE_BOTTOM: - { - // Top half slab block - a_BlockMeta = Meta | 0x08; - break; - } - case BLOCK_FACE_EAST: - case BLOCK_FACE_NORTH: - case BLOCK_FACE_SOUTH: - case BLOCK_FACE_WEST: - { - if (a_CursorPos.y > 7) - { - // Cursor at top half of block, place top slab - a_BlockMeta = Meta | 0x08; break; - } - else - { - // Cursor at bottom half of block, place bottom slab - a_BlockMeta = Meta & 0x07; break; - } - } - case BLOCK_FACE_NONE: return false; - } // switch (a_BlockFace) - - // Check if the block at the coordinates is a single slab. Eligibility for combining has already been processed in ClientHandle - // Changed to-be-placed to a double slab if we are clicking on a single slab, as opposed to placing one for the first time - if (IsAnySlabType(a_ChunkInterface.GetBlock(a_PlacedBlockPos))) - { - a_BlockType = GetDoubleSlabType(m_BlockType); - a_BlockMeta = a_BlockMeta & 0x07; + return false; } - return true; + const bool IsTopSlab = (a_Meta & 0x08) == 0x08; + const auto CanClickCombine = ((a_ClickedBlockFace == BLOCK_FACE_TOP) && !IsTopSlab) || ((a_ClickedBlockFace == BLOCK_FACE_BOTTOM) && IsTopSlab); + + /* When the player clicks on us directly, we'll combine if we're + a bottom slab and he clicked the top, or vice versa. Clicking on the sides will not combine. + However, when indirectly clicked (on the side of another block, that caused placement to go to us) + the conditions are exactly the opposite. */ + return a_ClickedDirectly ? CanClickCombine : !CanClickCombine; } @@ -131,24 +92,6 @@ private: - /** Converts the single-slab blocktype to its equivalent double-slab blocktype */ - static BLOCKTYPE GetDoubleSlabType(BLOCKTYPE a_SingleSlabBlockType) - { - switch (a_SingleSlabBlockType) - { - case E_BLOCK_STONE_SLAB: return E_BLOCK_DOUBLE_STONE_SLAB; - case E_BLOCK_WOODEN_SLAB: return E_BLOCK_DOUBLE_WOODEN_SLAB; - case E_BLOCK_RED_SANDSTONE_SLAB: return E_BLOCK_DOUBLE_RED_SANDSTONE_SLAB; - case E_BLOCK_PURPUR_SLAB: return E_BLOCK_PURPUR_DOUBLE_SLAB; - } - ASSERT(!"Unhandled slab type!"); - return E_BLOCK_AIR; - } - - - - - virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) const override { // Toggle the 4th bit - up / down: diff --git a/src/Blocks/BlockSnow.h b/src/Blocks/BlockSnow.h index 299ec9f62..f3fa87a1b 100644 --- a/src/Blocks/BlockSnow.h +++ b/src/Blocks/BlockSnow.h @@ -20,58 +20,21 @@ private: enum { - FullBlockMeta = 7 // Meta value of a full-height snow block + FullBlockMeta = 7 // Meta value of a full-height snow block. }; - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - a_BlockType = m_BlockType; - - // Check if incrementing existing snow height: - BLOCKTYPE BlockBeforePlacement; - NIBBLETYPE MetaBeforePlacement; - a_ChunkInterface.GetBlockTypeMeta(a_PlacedBlockPos, BlockBeforePlacement, MetaBeforePlacement); - if ((BlockBeforePlacement == E_BLOCK_SNOW) && (MetaBeforePlacement < FullBlockMeta)) - { - // Only increment if: - // - A snow block was already there (not first time placement) AND - // - Height is smaller than the maximum possible - a_BlockMeta = MetaBeforePlacement + 1; - return true; - } - - // First time placement, check placement is valid - a_BlockMeta = 0; - BLOCKTYPE BlockBelow; - NIBBLETYPE MetaBelow; - return ( - (a_PlacedBlockPos.y > 0) && - a_ChunkInterface.GetBlockTypeMeta(a_PlacedBlockPos.addedY(-1), BlockBelow, MetaBelow) && - CanBeOn(BlockBelow, MetaBelow) - ); - } - - - - - virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const override + virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, const NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const override { - if ((a_Player.GetEquippedItem().m_ItemType == E_BLOCK_SNOW) && (a_Meta < FullBlockMeta)) + if (a_Meta == 0) { - return true; // If a player is holding a (thin) snow block and it's size can be increased, return collision ignored + return true; // If at normal snowfall height (lowest), we ignore collision. } - if (a_Meta == 0) + // Special case if a player is holding a (thin) snow block and its size can be increased: + if ((a_HeldItem.m_ItemType == E_BLOCK_SNOW) && (a_Meta < FullBlockMeta)) { - return true; // If at normal snowfall height (lowest), we ignore collision + return !a_ClickedDirectly || (a_ClickedBlockFace == BLOCK_FACE_YP); // If clicked an adjacent block, or clicked YP directly, we ignore collision. } return false; @@ -83,7 +46,7 @@ private: virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override { - // No drop unless dug up with a shovel + // No drop unless dug up with a shovel: if ((a_Tool == nullptr) || !ItemCategory::IsShovel(a_Tool->m_ItemType)) { return {}; @@ -104,13 +67,13 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_RelPos.y <= 0) + if (a_Position.y <= 0) { return false; } - auto BelowPos = a_RelPos.addedY(-1); + auto BelowPos = a_Position.addedY(-1); auto BlockBelow = a_Chunk.GetBlock(BelowPos); auto MetaBelow = a_Chunk.GetMeta(BelowPos); return CanBeOn(BlockBelow, MetaBelow); @@ -141,7 +104,7 @@ private: /** Returns true if snow can be placed on top of a block with the given type and meta. */ static bool CanBeOn(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - // If block below is snowable, or it is a thin slow block and is a full thin snow block, say yay + // If block below is snowable, or it is a thin snow block and is a full thin snow block, say yay: return ( cBlockInfo::IsSnowable(a_BlockType) || ( diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h index 701ad38e1..55a9e877e 100644 --- a/src/Blocks/BlockStairs.h +++ b/src/Blocks/BlockStairs.h @@ -8,9 +8,9 @@ class cBlockStairsHandler final : - public cClearMetaOnDrop> + public cClearMetaOnDrop> { - using Super = cClearMetaOnDrop>; + using Super = cClearMetaOnDrop>; public: @@ -18,74 +18,6 @@ public: private: - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - UNUSED(a_ChunkInterface); - UNUSED(a_PlacedBlockPos); - UNUSED(a_CursorPos); - a_BlockType = m_BlockType; - a_BlockMeta = RotationToMetaData(a_Player.GetYaw()); - switch (a_ClickedBlockFace) - { - case BLOCK_FACE_TOP: break; - case BLOCK_FACE_BOTTOM: a_BlockMeta = a_BlockMeta | 0x4; break; // When placing onto a bottom face, always place an upside-down stairs block - case BLOCK_FACE_EAST: - case BLOCK_FACE_NORTH: - case BLOCK_FACE_SOUTH: - case BLOCK_FACE_WEST: - { - // When placing onto a sideways face, check cursor, if in top half, make it an upside-down stairs block - if (a_CursorPos.y > 8) - { - a_BlockMeta |= 0x4; - } - break; - } - case BLOCK_FACE_NONE: return false; - } - return true; - } - - - - - - static NIBBLETYPE RotationToMetaData(double a_Rotation) - { - a_Rotation += 90 + 45; // So its not aligned with axis - if (a_Rotation > 360) - { - a_Rotation -= 360; - } - if ((a_Rotation >= 0) && (a_Rotation < 90)) - { - return 0x0; - } - else if ((a_Rotation >= 180) && (a_Rotation < 270)) - { - return 0x1; - } - else if ((a_Rotation >= 90) && (a_Rotation < 180)) - { - return 0x2; - } - else - { - return 0x3; - } - } - - - - - virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) const override { // Toggle bit 3: diff --git a/src/Blocks/BlockStems.h b/src/Blocks/BlockStems.h index 1b6670264..f6686b25a 100644 --- a/src/Blocks/BlockStems.h +++ b/src/Blocks/BlockStems.h @@ -56,9 +56,9 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - return ((a_RelPos.y > 0) && (a_Chunk.GetBlock(a_RelPos.addedY(-1)) == E_BLOCK_FARMLAND)); + return (a_Position.y > 0) && (a_Chunk.GetBlock(a_Position.addedY(-1)) == E_BLOCK_FARMLAND); } diff --git a/src/Blocks/BlockSugarcane.h b/src/Blocks/BlockSugarcane.h index 1e802560d..bf5ae5e73 100644 --- a/src/Blocks/BlockSugarcane.h +++ b/src/Blocks/BlockSugarcane.h @@ -27,14 +27,14 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_RelPos.y <= 0) + if (a_Position.y <= 0) { return false; } - switch (a_Chunk.GetBlock(a_RelPos.addedY(-1))) + switch (a_Chunk.GetBlock(a_Position.addedY(-1))) { case E_BLOCK_DIRT: case E_BLOCK_GRASS: @@ -52,7 +52,7 @@ private: { BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - if (!a_Chunk.UnboundedRelGetBlock(a_RelPos + Coords[i], BlockType, BlockMeta)) + if (!a_Chunk.UnboundedRelGetBlock(a_Position + Coords[i], BlockType, BlockMeta)) { // Too close to the edge, cannot simulate return true; diff --git a/src/Blocks/BlockTallGrass.h b/src/Blocks/BlockTallGrass.h index 83f955a80..ea638c878 100644 --- a/src/Blocks/BlockTallGrass.h +++ b/src/Blocks/BlockTallGrass.h @@ -20,7 +20,7 @@ public: private: - virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const override + virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, const NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const override { return true; } @@ -52,14 +52,14 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - if (a_RelPos.y <= 0) + if (a_Position.y <= 0) { return false; } - BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelPos.addedY(-1)); + BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_Position.addedY(-1)); return IsBlockTypeOfDirt(BelowBlock); } diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h index c7bd4dcc8..0b96ad246 100644 --- a/src/Blocks/BlockTorch.h +++ b/src/Blocks/BlockTorch.h @@ -18,91 +18,6 @@ public: using Super::Super; -protected: - - ~cBlockTorchBaseHandler() = default; - -private: - - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - BLOCKTYPE ClickedBlockType; - NIBBLETYPE ClickedBlockMeta; - auto ClickedBlockPos = AddFaceDirection(a_PlacedBlockPos, a_ClickedBlockFace, true); - a_ChunkInterface.GetBlockTypeMeta(ClickedBlockPos, ClickedBlockType, ClickedBlockMeta); - if (!CanBePlacedOn(ClickedBlockType, ClickedBlockMeta, a_ClickedBlockFace)) - { - // Couldn't be placed on whatever face was clicked, last ditch resort - find another face - a_ClickedBlockFace = FindSuitableFace(a_ChunkInterface, a_PlacedBlockPos); // Set a_BlockFace to a valid direction which will be converted later to a metadata - if (a_ClickedBlockFace == BLOCK_FACE_NONE) - { - // No attachable face found - don't place the torch - return false; - } - } - a_BlockType = m_BlockType; - a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace); - return true; - } - - - - - - /** Converts the block face of the neighbor to which the torch is attached, to the torch block's meta. */ - inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_NeighborBlockFace) - { - switch (a_NeighborBlockFace) - { - case BLOCK_FACE_BOTTOM: ASSERT(!"Shouldn't be getting this face"); return 0; - case BLOCK_FACE_TOP: return E_META_TORCH_FLOOR; - case BLOCK_FACE_EAST: return E_META_TORCH_EAST; - case BLOCK_FACE_WEST: return E_META_TORCH_WEST; - case BLOCK_FACE_NORTH: return E_META_TORCH_NORTH; - case BLOCK_FACE_SOUTH: return E_META_TORCH_SOUTH; - case BLOCK_FACE_NONE: - { - ASSERT(!"Unhandled torch direction!"); - break; - } - } - return 0x0; - } - - - - - - /** Converts the torch block's meta to the block face of the neighbor to which the torch is attached. */ - inline static eBlockFace MetaDataToBlockFace(NIBBLETYPE a_MetaData) - { - switch (a_MetaData) - { - case 0: return BLOCK_FACE_TOP; // By default, the torches stand on the ground - case E_META_TORCH_FLOOR: return BLOCK_FACE_TOP; - case E_META_TORCH_EAST: return BLOCK_FACE_EAST; - case E_META_TORCH_WEST: return BLOCK_FACE_WEST; - case E_META_TORCH_NORTH: return BLOCK_FACE_NORTH; - case E_META_TORCH_SOUTH: return BLOCK_FACE_SOUTH; - default: - { - ASSERT(!"Unhandled torch metadata"); - break; - } - } - return BLOCK_FACE_TOP; - } - - - - /** Returns true if the torch can be placed on the specified block's face. */ static bool CanBePlacedOn(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_BlockFace) @@ -163,37 +78,40 @@ private: } } +protected: + ~cBlockTorchBaseHandler() = default; +private: - - /** Returns a suitable neighbor's blockface to place the torch at the specified pos - Returns BLOCK_FACE_NONE on failure */ - static eBlockFace FindSuitableFace(cChunkInterface & a_ChunkInterface, const Vector3i a_TorchPos) + /** Converts the torch block's meta to the block face of the neighbor to which the torch is attached. */ + inline static eBlockFace MetaDataToBlockFace(NIBBLETYPE a_MetaData) { - for (int i = BLOCK_FACE_YM; i <= BLOCK_FACE_XP; i++) // Loop through all faces + switch (a_MetaData) { - auto Face = static_cast(i); - auto NeighborPos = AddFaceDirection(a_TorchPos, Face, true); - BLOCKTYPE NeighborBlockType; - NIBBLETYPE NeighborBlockMeta; - a_ChunkInterface.GetBlockTypeMeta(NeighborPos, NeighborBlockType, NeighborBlockMeta); - if (CanBePlacedOn(NeighborBlockType, NeighborBlockMeta, Face)) + case 0: return BLOCK_FACE_TOP; // By default, the torches stand on the ground + case E_META_TORCH_FLOOR: return BLOCK_FACE_TOP; + case E_META_TORCH_EAST: return BLOCK_FACE_EAST; + case E_META_TORCH_WEST: return BLOCK_FACE_WEST; + case E_META_TORCH_NORTH: return BLOCK_FACE_NORTH; + case E_META_TORCH_SOUTH: return BLOCK_FACE_SOUTH; + default: { - return Face; + ASSERT(!"Unhandled torch metadata"); + break; } } - return BLOCK_FACE_NONE; + return BLOCK_FACE_TOP; } - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - auto Face = MetaDataToBlockFace(a_Chunk.GetMeta(a_RelPos)); - auto NeighborRelPos = AddFaceDirection(a_RelPos, Face, true); + auto Face = MetaDataToBlockFace(a_Meta); + auto NeighborRelPos = AddFaceDirection(a_Position, Face, true); BLOCKTYPE NeighborBlockType; NIBBLETYPE NeighborBlockMeta; if (!a_Chunk.UnboundedRelGetBlock(NeighborRelPos, NeighborBlockType, NeighborBlockMeta)) diff --git a/src/Blocks/BlockTrapdoor.h b/src/Blocks/BlockTrapdoor.h index cef7fb6e9..7f6f70e1e 100644 --- a/src/Blocks/BlockTrapdoor.h +++ b/src/Blocks/BlockTrapdoor.h @@ -71,74 +71,6 @@ private: - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - if (a_ClickedBlockFace == BLOCK_FACE_YP) - { - // Trapdoor is placed on top of a block. - // Engage yaw rotation to determine hinge direction: - return Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, a_BlockMeta); - } - else if (a_ClickedBlockFace == BLOCK_FACE_YM) - { - // Trapdoor is placed on bottom of a block. - // Engage yaw rotation to determine hinge direction: - if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, a_BlockMeta)) - { - return false; - } - - // Toggle 'Move up half-block' bit on: - a_BlockMeta |= 0x8; - - return true; - } - - // Placement on block sides; hinge direction is determined by which side was clicked: - a_BlockType = m_BlockType; - a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace); - - if (a_CursorPos.y > 7) - { - // Trapdoor is placed on a higher half of a vertical block. - // Toggle 'Move up half-block' bit on: - a_BlockMeta |= 0x8; - } - - return true; - } - - - - - - inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace) - { - switch (a_BlockFace) - { - case BLOCK_FACE_ZP: return 0x1; - case BLOCK_FACE_ZM: return 0x0; - case BLOCK_FACE_XP: return 0x3; - case BLOCK_FACE_XM: return 0x2; - default: - { - ASSERT(!"Unhandled block face!"); - return 0; - } - } - } - - - - - inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta) { switch (a_Meta & 0x3) diff --git a/src/Blocks/BlockTripwireHook.h b/src/Blocks/BlockTripwireHook.h index 0d58bb084..ae553d66f 100644 --- a/src/Blocks/BlockTripwireHook.h +++ b/src/Blocks/BlockTripwireHook.h @@ -30,57 +30,9 @@ public: private: - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - a_BlockType = m_BlockType; - - switch (a_ClickedBlockFace) - { - case BLOCK_FACE_XM: - { - a_BlockMeta = 0x1; - return true; - } - case BLOCK_FACE_XP: - { - a_BlockMeta = 0x3; - return true; - } - case BLOCK_FACE_ZM: - { - a_BlockMeta = 0x2; - return true; - } - case BLOCK_FACE_ZP: - { - a_BlockMeta = 0x0; - return true; - } - case BLOCK_FACE_NONE: - case BLOCK_FACE_YM: - case BLOCK_FACE_YP: - { - return false; - } - } - UNREACHABLE("Unsupported block face"); - } - - - - - - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override - { - const auto Meta = a_Chunk.GetMeta(a_RelPos); - const auto RearPosition = AddFaceDirection(a_RelPos, MetadataToDirection(Meta), true); + const auto RearPosition = AddFaceDirection(a_Position, MetadataToDirection(a_Meta), true); BLOCKTYPE NeighborBlockType; if (!a_Chunk.UnboundedRelGetBlockType(RearPosition, NeighborBlockType)) diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h index 51f6112bc..da4d6dfc3 100644 --- a/src/Blocks/BlockVine.h +++ b/src/Blocks/BlockVine.h @@ -17,33 +17,14 @@ public: private: - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - // TODO: Disallow placement where the vine doesn't attach to something properly - BLOCKTYPE BlockType = 0; - NIBBLETYPE BlockMeta; - a_ChunkInterface.GetBlockTypeMeta(a_PlacedBlockPos, BlockType, BlockMeta); - if (BlockType == m_BlockType) - { - a_BlockMeta = BlockMeta | DirectionToMetaData(a_ClickedBlockFace); - } - else - { - a_BlockMeta = DirectionToMetaData(a_ClickedBlockFace); - } - a_BlockType = m_BlockType; - return true; - } - + static const NIBBLETYPE VINE_LOST_SUPPORT = 16; + static const NIBBLETYPE VINE_UNCHANGED = 17; + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override + { + return GetMaxMeta(a_Chunk, a_Position, a_Meta) != VINE_LOST_SUPPORT; + } virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override @@ -60,22 +41,6 @@ private: - static NIBBLETYPE DirectionToMetaData(char a_BlockFace) - { - switch (a_BlockFace) - { - case BLOCK_FACE_NORTH: return 0x1; - case BLOCK_FACE_SOUTH: return 0x4; - case BLOCK_FACE_WEST: return 0x8; - case BLOCK_FACE_EAST: return 0x2; - default: return 0x0; - } - } - - - - - static char MetaDataToDirection(NIBBLETYPE a_MetaData) { switch (a_MetaData) @@ -122,8 +87,9 @@ private: - /** Returns the meta that has the maximum allowable sides of the vine, given the surroundings */ - static NIBBLETYPE GetMaxMeta(cChunk & a_Chunk, Vector3i a_RelPos) + /** Returns the meta that has the maximum allowable sides of the vine, given the surroundings and current vine meta. + Returns special values for a vine that can continue to exist unchanged, or must die completely. */ + static NIBBLETYPE GetMaxMeta(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_CurrentMeta) { static const struct { @@ -136,21 +102,41 @@ private: { 0, -1, 4}, // north, ZM { 1, 0, 8}, // east, XP } ; - NIBBLETYPE res = 0; + + NIBBLETYPE MaxMeta = 0; for (auto & Coord : Coords) { BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - auto checkPos = a_RelPos.addedXZ(Coord.x, Coord.z); + auto checkPos = a_Position.addedXZ(Coord.x, Coord.z); if ( a_Chunk.UnboundedRelGetBlock(checkPos.x, checkPos.y, checkPos.z, BlockType, BlockMeta) && IsBlockAttachable(BlockType) ) { - res |= Coord.Bit; + MaxMeta |= Coord.Bit; } } - return res; + + // Check if vine above us, add its meta to MaxMeta: + if ((a_Position.y < cChunkDef::Height - 1) && (a_Chunk.GetBlock(a_Position.addedY(1)) == E_BLOCK_VINES)) + { + MaxMeta |= a_Chunk.GetMeta(a_Position.addedY(1)); + } + + NIBBLETYPE Common = a_CurrentMeta & MaxMeta; // Neighbors that we have and are legal. + if (Common != a_CurrentMeta) + { + bool HasTop = (a_Position.y < (cChunkDef::Height - 1)) && IsBlockAttachable(a_Chunk.GetBlock(a_Position.addedY(1))); + if ((Common == 0) && !HasTop) // Meta equals 0 also means top. Make a last-ditch attempt to save the vine. + { + return VINE_LOST_SUPPORT; + } + + return Common; + } + + return VINE_UNCHANGED; } @@ -162,28 +148,25 @@ private: a_ChunkInterface.DoWithChunkAt(a_BlockPos, [&](cChunk & a_Chunk) { - const auto a_RelPos = cChunkDef::AbsoluteToRelative(a_BlockPos); - NIBBLETYPE CurMeta = a_Chunk.GetMeta(a_RelPos); - NIBBLETYPE MaxMeta = GetMaxMeta(a_Chunk, a_RelPos); + const auto Position = cChunkDef::AbsoluteToRelative(a_BlockPos); + const auto MaxMeta = GetMaxMeta(a_Chunk, Position, a_Chunk.GetMeta(Position)); - // Check if vine above us, add its meta to MaxMeta - if ((a_RelPos.y < cChunkDef::Height - 1) && (a_Chunk.GetBlock(a_RelPos.addedY(1)) == m_BlockType)) + if (MaxMeta == VINE_UNCHANGED) { - MaxMeta |= a_Chunk.GetMeta(a_RelPos.addedY(1)); + return false; } - NIBBLETYPE Common = CurMeta & MaxMeta; // Neighbors that we have and are legal - if (Common != CurMeta) + // There is a neighbor missing, need to update the meta or even destroy the block. + + if (MaxMeta == VINE_LOST_SUPPORT) { - // There is a neighbor missing, need to update the meta or even destroy the block - bool HasTop = (a_RelPos.y < cChunkDef::Height - 1) && IsBlockAttachable(a_Chunk.GetBlock(a_RelPos.addedY(1))); - if ((Common == 0) && !HasTop) - { - // The vine just lost all its support, destroy the block: - a_Chunk.SetBlock(a_RelPos, E_BLOCK_AIR, 0); - return false; - } - a_Chunk.SetBlock(a_RelPos, m_BlockType, Common); + // The vine just lost all its support, destroy the block: + a_Chunk.SetBlock(Position, E_BLOCK_AIR, 0); + } + else + { + // It lost some of its support, set it to what remains (SetBlock to notify neighbors): + a_Chunk.SetBlock(Position, E_BLOCK_VINES, MaxMeta); } return false; @@ -194,9 +177,9 @@ private: - virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const override + virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, const NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const override { - return true; + return !a_ClickedDirectly || (a_HeldItem.m_ItemType != m_BlockType); } diff --git a/src/Blocks/BlockWallSign.h b/src/Blocks/BlockWallSign.h index 2e6f7a45b..f19e408fa 100644 --- a/src/Blocks/BlockWallSign.h +++ b/src/Blocks/BlockWallSign.h @@ -17,25 +17,6 @@ public: using Super::Super; - /** Converts the block face of the neighbor to which the wallsign is attached to the wallsign block's meta. */ - static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_NeighborBlockFace) - { - switch (a_NeighborBlockFace) - { - case BLOCK_FACE_ZM: return 0x02; - case BLOCK_FACE_ZP: return 0x03; - case BLOCK_FACE_XM: return 0x04; - case BLOCK_FACE_XP: return 0x05; - case BLOCK_FACE_NONE: - case BLOCK_FACE_YP: - case BLOCK_FACE_YM: - { - break; - } - } - return 0x02; - } - private: virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override @@ -47,16 +28,16 @@ private: - virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const override + virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const override { - auto NeighborPos = a_RelPos + GetOffsetBehindTheSign(a_Chunk.GetMeta(a_RelPos)); + auto NeighborPos = a_Position + GetOffsetBehindTheSign(a_Meta); BLOCKTYPE NeighborType; if (!a_Chunk.UnboundedRelGetBlockType(NeighborPos, NeighborType)) { // The neighbor is not accessible (unloaded chunk), bail out without changing this return true; } - return ((NeighborType == E_BLOCK_WALLSIGN) || (NeighborType == E_BLOCK_SIGN_POST) || cBlockInfo::IsSolid(NeighborType)); + return (NeighborType == E_BLOCK_WALLSIGN) || (NeighborType == E_BLOCK_SIGN_POST) || cBlockInfo::IsSolid(NeighborType); } diff --git a/src/Blocks/Mixins.h b/src/Blocks/Mixins.h index 42b437ba7..23a4be225 100644 --- a/src/Blocks/Mixins.h +++ b/src/Blocks/Mixins.h @@ -167,27 +167,6 @@ public: using Super::Super; - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - const Vector3i a_BlockPos, - eBlockFace a_BlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override - { - NIBBLETYPE BaseMeta; - if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_BlockPos, a_BlockFace, a_CursorPos, a_BlockType, BaseMeta)) - { - return false; - } - - a_BlockMeta = (BaseMeta & ~BitMask) | YawToMetaData(a_Player.GetYaw()); - return true; - } - - - - /** Converts the rotation value as returned by cPlayer::GetYaw() to the appropriate metadata value for a block placed by a player facing that way */ @@ -241,31 +220,26 @@ public: using Super::Super; -protected: - - ~cPitchYawRotator() = default; - virtual bool GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, - cPlayer & a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) const override + /** Converts the rotation and pitch values as returned by cPlayer::GetYaw() and cPlayer::GetPitch() + respectively to the appropriate metadata value for a block placed by a player facing that way */ + static NIBBLETYPE PitchYawToMetaData(double a_Rotation, double a_Pitch) { - NIBBLETYPE BaseMeta; - if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, BaseMeta)) + if (a_Pitch >= 50) { - return false; + return Up; + } + else if (a_Pitch <= -50) + { + return Down; } - a_BlockMeta = (BaseMeta & ~BitMask) | PitchYawToMetaData(a_Player.GetYaw(), a_Player.GetPitch()); - return true; + return Super::YawToMetaData(a_Rotation); } +protected: - + ~cPitchYawRotator() = default; virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) const override @@ -279,24 +253,4 @@ protected: // Not Facing Up or Down; No change. return a_Meta; } - - - - - - /** Converts the rotation and pitch values as returned by cPlayer::GetYaw() and cPlayer::GetPitch() - respectively to the appropriate metadata value for a block placed by a player facing that way */ - static NIBBLETYPE PitchYawToMetaData(double a_Rotation, double a_Pitch) - { - if (a_Pitch >= 50) - { - return Up; - } - else if (a_Pitch <= -50) - { - return Down; - } - - return Super::YawToMetaData(a_Rotation); - } }; diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h index b610bd9ac..b3fc9878d 100644 --- a/src/Blocks/WorldInterface.h +++ b/src/Blocks/WorldInterface.h @@ -54,10 +54,10 @@ public: virtual std::vector SpawnSplitExperienceOrbs(Vector3d a_Pos, int a_Reward) = 0; /** Sends the block on those coords to the player */ - virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer & a_Player) = 0; + virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, const cPlayer & a_Player) = 0; /** Sends the block on those coords to the player */ - inline void SendBlockTo(const Vector3i a_BlockPos, cPlayer & a_Player) + inline void SendBlockTo(const Vector3i a_BlockPos, const cPlayer & a_Player) { SendBlockTo(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Player); } diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 669a4f564..9e39338de 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -748,6 +748,10 @@ bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure) res = false; continue; } + if (!cChunkDef::IsValidHeight(itr->m_RelY)) + { + continue; + } itr->m_BlockType = Chunk->GetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ); itr->m_BlockMeta = Chunk->GetMeta(itr->m_RelX, itr->m_RelY, itr->m_RelZ); } @@ -798,7 +802,7 @@ cItems cChunkMap::PickupsFromBlock(Vector3i a_BlockPos, const cEntity * a_Digger -void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer & a_Player) +void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, const cPlayer & a_Player) { int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_X, a_Y, a_Z, ChunkX, ChunkZ); diff --git a/src/ChunkMap.h b/src/ChunkMap.h index d0aeb867c..b3cc5f615 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -153,7 +153,7 @@ public: /** Sends the block at the specified coords to the specified player. Uses a blockchange packet to send the block. If the relevant chunk isn't loaded, doesn't do anything. */ - void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer & a_Player); + void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, const cPlayer & a_Player); /** Compares clients of two chunks, calls the callback accordingly */ void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback); diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 4ee5a1c65..1edd612b1 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -987,15 +987,13 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB /* Check for clickthrough-blocks: When the user breaks a fire block, the client send the wrong block location. We must find the right block with the face direction. */ + int BlockX = a_BlockX; int BlockY = a_BlockY; int BlockZ = a_BlockZ; AddFaceDirection(BlockX, BlockY, BlockZ, a_BlockFace); - if ( - cChunkDef::IsValidHeight(BlockY) && - cBlockHandler::For(m_Player->GetWorld()->GetBlock({ BlockX, BlockY, BlockZ })).IsClickedThrough() - ) + if (cChunkDef::IsValidHeight(BlockY) && cBlockInfo::IsClickedThrough(m_Player->GetWorld()->GetBlock({ BlockX, BlockY, BlockZ }))) { a_BlockX = BlockX; a_BlockY = BlockY; @@ -1338,7 +1336,6 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e cWorld * World = m_Player->GetWorld(); cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager(); - bool Success = false; if ( !PlgMgr->CallHookPlayerRightClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ) && IsWithinReach && !m_Player->IsFrozen() @@ -1354,29 +1351,24 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e if (BlockUsable && !(m_Player->IsCrouched() && !HeldItem.IsEmpty())) { - // use a block cChunkInterface ChunkInterface(World->GetChunkMap()); if (!PlgMgr->CallHookPlayerUsingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta)) { + // Use a block: if (BlockHandler.OnUse(ChunkInterface, *World, *m_Player, ClickedBlockPos, a_BlockFace, CursorPos)) { - // block use was successful, we're done PlgMgr->CallHookPlayerUsedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta); - Success = true; + return; // Block use was successful, we're done. } - // Check if the item is place able, for example a torch on a fence - if (!Success && Placeable) + // Check if the item is place able, for example a torch on a fence: + if (Placeable) { - // place a block - Success = ItemHandler->OnPlayerPlace(*World, *m_Player, HeldItem, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace, {a_CursorX, a_CursorY, a_CursorZ}); + // Place a block: + ItemHandler->OnPlayerPlace(*m_Player, HeldItem, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace, {a_CursorX, a_CursorY, a_CursorZ}); } - } - else - { - // TODO: OnCancelRightClick seems to do the same thing with updating blocks at the end of this function. Need to double check - // A plugin doesn't agree with the action, replace the block on the client and quit: - BlockHandler.OnCancelRightClick(ChunkInterface, *World, *m_Player, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace); + + return; } } else if (Placeable) @@ -1388,36 +1380,30 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e Kick("Too many blocks were placed / interacted with per unit time - hacked client?"); return; } - // place a block - Success = ItemHandler->OnPlayerPlace(*World, *m_Player, HeldItem, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace, {a_CursorX, a_CursorY, a_CursorZ}); - } - else - { - // Use an item in hand with a target block - if (!PlgMgr->CallHookPlayerUsingItem(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ)) - { - // All plugins agree with using the item - cBlockInServerPluginInterface PluginInterface(*World); - ItemHandler->OnItemUse(World, m_Player, PluginInterface, HeldItem, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace); - PlgMgr->CallHookPlayerUsedItem(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ); - Success = true; - } + + // Place a block: + ItemHandler->OnPlayerPlace(*m_Player, HeldItem, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace, {a_CursorX, a_CursorY, a_CursorZ}); + return; } - } - if (!Success) - { - // Update the target block including the block above and below for 2 block high things - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); - for (int y = a_BlockY - 1; y <= a_BlockY + 1; y++) + else if (!PlgMgr->CallHookPlayerUsingItem(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ)) { - if (cChunkDef::IsValidHeight(y)) - { - World->SendBlockTo(a_BlockX, y, a_BlockZ, *m_Player); - } + // All plugins agree with using the item. + // Use an item in hand with a target block. + + cBlockInServerPluginInterface PluginInterface(*World); + ItemHandler->OnItemUse(World, m_Player, PluginInterface, HeldItem, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace); + PlgMgr->CallHookPlayerUsedItem(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ); + return; } - // TODO: Send corresponding slot based on hand - m_Player->GetInventory().SendEquippedSlot(); } + + // TODO: delete OnItemUse bool return, delete onCancelRightClick + + // Update the target block including the block above and below for 2 block high things: + m_Player->SendBlocksAround(a_BlockX, a_BlockY, a_BlockZ, 2); + + // TODO: Send corresponding slot based on hand + m_Player->GetInventory().SendEquippedSlot(); } diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 08adb1096..235433cf8 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -2391,10 +2391,9 @@ void cPlayer::LoadRank(void) -bool cPlayer::PlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +bool cPlayer::PlaceBlock(const Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - sSetBlockVector blk{{a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta}}; - return PlaceBlocks(blk); + return PlaceBlocks({ { a_Position, a_BlockType, a_BlockMeta } }); } @@ -2442,7 +2441,7 @@ void cPlayer::SendBlocksAround(int a_BlockX, int a_BlockY, int a_BlockZ, int a_R -bool cPlayer::DoesPlacingBlocksIntersectEntity(const sSetBlockVector & a_Blocks) +bool cPlayer::DoesPlacingBlocksIntersectEntity(const std::initializer_list a_Blocks) const { // Compute the bounding box for each block to be placed std::vector PlacementBoxes; @@ -2516,44 +2515,52 @@ const cUUID & cPlayer::GetUUID(void) const -bool cPlayer::PlaceBlocks(const sSetBlockVector & a_Blocks) +bool cPlayer::PlaceBlocks(const std::initializer_list a_Blocks) { if (DoesPlacingBlocksIntersectEntity(a_Blocks)) { // Abort - re-send all the current blocks in the a_Blocks' coords to the client: - for (auto blk2: a_Blocks) + for (const auto & ResendBlock : a_Blocks) { - m_World->SendBlockTo(blk2.GetX(), blk2.GetY(), blk2.GetZ(), *this); + m_World->SendBlockTo(ResendBlock.GetX(), ResendBlock.GetY(), ResendBlock.GetZ(), *this); } return false; } - // Call the "placing" hooks; if any fail, abort: cPluginManager * pm = cPluginManager::Get(); - for (auto blk: a_Blocks) + + // Check the blocks CanBeAt, and call the "placing" hooks; if any fail, abort: + for (const auto & Block : a_Blocks) { - if (pm->CallHookPlayerPlacingBlock(*this, blk)) + if ( + !m_World->DoWithChunkAt(Block.GetAbsolutePos(), [&Block](cChunk & a_Chunk) + { + return cBlockHandler::For(Block.m_BlockType).CanBeAt(a_Chunk, Block.GetRelativePos(), Block.m_BlockMeta); + }) + ) + { + return false; + } + + if (pm->CallHookPlayerPlacingBlock(*this, Block)) { // Abort - re-send all the current blocks in the a_Blocks' coords to the client: - for (auto blk2: a_Blocks) + for (const auto & ResendBlock : a_Blocks) { - m_World->SendBlockTo(blk2.GetX(), blk2.GetY(), blk2.GetZ(), *this); + m_World->SendBlockTo(ResendBlock.GetX(), ResendBlock.GetY(), ResendBlock.GetZ(), *this); } return false; } - } // for blk - a_Blocks[] + } cChunkInterface ChunkInterface(m_World->GetChunkMap()); - for (auto blk: a_Blocks) + for (const auto & Block : a_Blocks) { // Set the blocks: - m_World->PlaceBlock(blk.GetAbsolutePos(), blk.m_BlockType, blk.m_BlockMeta); - - // Notify the blockhandlers: - cBlockHandler::For(blk.m_BlockType).OnPlacedByPlayer(ChunkInterface, *m_World, *this, blk); + m_World->PlaceBlock(Block.GetAbsolutePos(), Block.m_BlockType, Block.m_BlockMeta); // Call the "placed" hooks: - pm->CallHookPlayerPlacedBlock(*this, blk); + pm->CallHookPlayerPlacedBlock(*this, Block); } return true; diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 987bccbe5..f4ce76f21 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -534,7 +534,7 @@ public: void UpdateMovementStats(const Vector3d & a_DeltaPos, bool a_PreviousIsOnGround); /** Whether placing the given blocks would intersect any entitiy */ - bool DoesPlacingBlocksIntersectEntity(const sSetBlockVector & a_Blocks); + bool DoesPlacingBlocksIntersectEntity(std::initializer_list a_Blocks) const; /** Returns the UUID that has been read from the client, or nil if not available. */ const cUUID & GetUUID(void) const; // Exported in ManualBindings.cpp @@ -552,7 +552,7 @@ public: If the hook prevents the placement, sends the current block at the specified coords back to the client. Assumes that the block is in a currently loaded chunk. Returns true if the block is successfully placed. */ - bool PlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); + bool PlaceBlock(Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); /** Sends the block in the specified range around the specified coord to the client as a block change packet. @@ -571,7 +571,7 @@ public: If the any of the "placing" hooks aborts, none of the blocks are placed and the function returns false. Returns true if all the blocks are placed. Assumes that all the blocks are in currently loaded chunks. */ - bool PlaceBlocks(const sSetBlockVector & a_Blocks); + bool PlaceBlocks(std::initializer_list a_Blocks); /** Notify nearby wolves that the player or one of the player's wolves took damage or did damage to an entity @param a_Opponent the opponent we're fighting. diff --git a/src/Items/CMakeLists.txt b/src/Items/CMakeLists.txt index 0046386d0..3f182dd76 100644 --- a/src/Items/CMakeLists.txt +++ b/src/Items/CMakeLists.txt @@ -3,6 +3,7 @@ target_sources( ItemHandler.cpp + ItemAnvil.h ItemArmor.h ItemAxe.h ItemBanner.h @@ -12,24 +13,35 @@ target_sources( ItemBottle.h ItemBow.h ItemBucket.h + ItemButton.h ItemChest.h ItemCloth.h ItemComparator.h ItemCookedFish.h ItemDoor.h + ItemDropSpenser.h ItemDye.h ItemEmptyMap.h ItemEnchantingTable.h ItemEndCrystal.h + ItemEndPortalFrame.h + ItemEnderchest.h ItemEyeOfEnder.h + ItemFenceGate.h ItemFishingRod.h ItemFood.h ItemFoodSeeds.h + ItemFurnace.h + ItemGlazedTerracotta.h ItemGoldenApple.h ItemHandler.h ItemHoe.h + ItemHopper.h ItemItemFrame.h + ItemJackOLantern.h + ItemLadder.h ItemLeaves.h + ItemLever.h ItemLighter.h ItemLilypad.h ItemMap.h @@ -37,11 +49,16 @@ target_sources( ItemMinecart.h ItemMobHead.h ItemNetherWart.h + ItemObserver.h ItemPainting.h ItemPickaxe.h + ItemPiston.h + ItemPlanks.h ItemPoisonousPotato.h ItemPotion.h ItemPumpkin.h + ItemQuartz.h + ItemRail.h ItemRawChicken.h ItemRawFish.h ItemRedstoneDust.h @@ -51,12 +68,19 @@ target_sources( ItemSeeds.h ItemShears.h ItemShovel.h + ItemSideways.h ItemSign.h ItemSlab.h + ItemSnow.h ItemSoup.h ItemSpawnEgg.h ItemSpiderEye.h + ItemStairs.h ItemSword.h ItemThrowable.h + ItemTorch.h + ItemTrapdoor.h + ItemTripwireHook.h + ItemVine.h SimplePlaceableItemHandler.h ) diff --git a/src/Items/ItemAnvil.h b/src/Items/ItemAnvil.h new file mode 100644 index 000000000..e52f28e65 --- /dev/null +++ b/src/Items/ItemAnvil.h @@ -0,0 +1,30 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockAnvil.h" + + + + + +class cItemAnvilHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + return a_Player.PlaceBlock( + a_PlacePosition, + static_cast(a_HeldItem.m_ItemType), + cBlockAnvilHandler::YawToMetaData(a_Player.GetYaw()) | static_cast(a_HeldItem.m_ItemDamage << 2) + ); + } +}; diff --git a/src/Items/ItemBanner.h b/src/Items/ItemBanner.h index 3f082c5a5..2ebfca44a 100644 --- a/src/Items/ItemBanner.h +++ b/src/Items/ItemBanner.h @@ -24,6 +24,32 @@ public: { } +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + // Cannot place a banner at "no face" and from the bottom: + if ((a_ClickedBlockFace == BLOCK_FACE_NONE) || (a_ClickedBlockFace == BLOCK_FACE_BOTTOM)) + { + return false; + } + + if (!TryPlaceBanner(a_Player, a_PlacePosition, a_ClickedBlockFace)) + { + return false; + } + + a_Player.GetWorld()->DoWithBlockEntityAt(a_PlacePosition, [&a_HeldItem](cBlockEntity & a_BlockEntity) + { + ASSERT((a_BlockEntity.GetBlockType() == E_BLOCK_STANDING_BANNER) || (a_BlockEntity.GetBlockType() == E_BLOCK_WALL_BANNER)); + + static_cast(a_BlockEntity).SetBaseColor(static_cast(a_HeldItem.m_ItemDamage)); + return false; + }); + + return true; + } + @@ -36,182 +62,120 @@ public: - - virtual bool GetPlacementBlockTypeMeta( - cWorld * a_World, cPlayer * a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) override + static bool TryPlaceBanner(cPlayer & a_Player, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace) { - a_BlockMeta = 0x00; - const double Rotation = a_Player->GetYaw(); + const auto Rotation = a_Player.GetYaw(); - // Placing on the floor + // Placing on the floor: if (a_ClickedBlockFace == BLOCK_FACE_TOP) { - if ((Rotation >= - 11.25f) && (Rotation < 11.25f)) + NIBBLETYPE Meta; + + if ((Rotation >= -11.25f) && (Rotation < 11.25f)) { // South - a_BlockMeta |= 0x08; + Meta = 0x08; } else if ((Rotation >= 11.25f) && (Rotation < 33.75f)) { // SouthSouthWest - a_BlockMeta |= 0x09; + Meta = 0x09; } else if ((Rotation >= 23.75f) && (Rotation < 56.25f)) { // SouthWest - a_BlockMeta |= 0x0a; + Meta = 0x0a; } else if ((Rotation >= 56.25f) && (Rotation < 78.75f)) { // WestSouthWest - a_BlockMeta |= 0x0b; + Meta = 0x0b; } else if ((Rotation >= 78.75f) && (Rotation < 101.25f)) { // West - a_BlockMeta |= 0x0c; + Meta = 0x0c; } else if ((Rotation >= 101.25f) && (Rotation < 123.75f)) { // WestNorthWest - a_BlockMeta |= 0x0d; + Meta = 0x0d; } else if ((Rotation >= 123.75f) && (Rotation < 146.25f)) { // NorthWest - a_BlockMeta |= 0x0e; + Meta = 0x0e; } else if ((Rotation >= 146.25f) && (Rotation < 168.75f)) { // NorthNorthWest - a_BlockMeta |= 0x0f; + Meta = 0x0f; } else if ((Rotation >= -168.75f) && (Rotation < -146.25f)) { // NorthNorthEast - a_BlockMeta |= 0x01; + Meta = 0x01; } else if ((Rotation >= -146.25f) && (Rotation < -123.75f)) { // NorthEast - a_BlockMeta |= 0x02; + Meta = 0x02; } else if ((Rotation >= -123.75f) && (Rotation < -101.25f)) { // EastNorthEast - a_BlockMeta |= 0x03; + Meta = 0x03; } else if ((Rotation >= -101.25) && (Rotation < -78.75f)) { // East - a_BlockMeta |= 0x04; + Meta = 0x04; } else if ((Rotation >= -78.75) && (Rotation < -56.25f)) { // EastSouthEast - a_BlockMeta |= 0x05; + Meta = 0x05; } else if ((Rotation >= -56.25f) && (Rotation < -33.75f)) { // SouthEast - a_BlockMeta |= 0x06; + Meta = 0x06; } else if ((Rotation >= -33.75f) && (Rotation < -11.25f)) { // SouthSouthEast - a_BlockMeta |= 0x07; + Meta = 0x07; } else // degrees jumping from 180 to -180 { // North - a_BlockMeta |= 0x00; - } - a_BlockType = E_BLOCK_STANDING_BANNER; - } - // placing on the sides - else if (a_ClickedBlockFace != BLOCK_FACE_NONE) - { - if (a_ClickedBlockFace == BLOCK_FACE_EAST) - { - a_BlockMeta |= 0x05; - } - else if (a_ClickedBlockFace == BLOCK_FACE_WEST) - { - a_BlockMeta |= 0x04; + Meta = 0x00; } - else if (a_ClickedBlockFace == BLOCK_FACE_NORTH) - { - a_BlockMeta |= 0x02; - } - else // degrees jumping from 180 to -180 - { - a_BlockMeta |= 0x03; - } - a_BlockType = E_BLOCK_WALL_BANNER; - } - else - { - return false; - } - - return true; - } - + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_STANDING_BANNER, Meta); + } + // We must be placing on the side of a block. + NIBBLETYPE Meta; - virtual bool OnPlayerPlace( - cWorld & a_World, - cPlayer & a_Player, - const cItem & a_EquippedItem, - const Vector3i a_ClickedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos - ) override - { - // Cannot place a banner at "no face" and from the bottom: - if ((a_ClickedBlockFace == BLOCK_FACE_NONE) || (a_ClickedBlockFace == BLOCK_FACE_BOTTOM)) + if (a_ClickedBlockFace == BLOCK_FACE_EAST) { - return true; + Meta = 0x05; } - - // Checks if the banner replaced the block - BLOCKTYPE ClickedBlockType; - NIBBLETYPE ClickedBlockMeta; - a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta); - cChunkInterface ChunkInterface(a_World.GetChunkMap()); - bool IsReplacingClickedBlock = cBlockHandler::For(ClickedBlockType).DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, a_Player, ClickedBlockMeta); - if (IsReplacingClickedBlock) + else if (a_ClickedBlockFace == BLOCK_FACE_WEST) { - // TODO: There is a bug in the network which prevents the client from receiving the new block entity on placement - // For now the replaced blocks are disabled - return false; + Meta = 0x04; } - - // saving the color of the banner in case it's the players last one - NIBBLETYPE Color = static_cast(a_EquippedItem.m_ItemDamage); - - if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_ClickedBlockPos)) + else if (a_ClickedBlockFace == BLOCK_FACE_NORTH) { - return false; + Meta = 0x02; } - - const auto BannerPos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); - a_World.DoWithBlockEntityAt(BannerPos, [Color](cBlockEntity & a_BlockEntity) + else // degrees jumping from 180 to -180 { - ASSERT((a_BlockEntity.GetBlockType() == E_BLOCK_STANDING_BANNER) || (a_BlockEntity.GetBlockType() == E_BLOCK_WALL_BANNER)); - - auto & Banner = static_cast(a_BlockEntity); - Banner.SetBaseColor(Color); - return false; - }); + Meta = 0x03; + } - return true; + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_WALL_BANNER, Meta); } }; diff --git a/src/Items/ItemBed.h b/src/Items/ItemBed.h index 98f9f614f..7b8dde637 100644 --- a/src/Items/ItemBed.h +++ b/src/Items/ItemBed.h @@ -2,8 +2,8 @@ #pragma once #include "ItemHandler.h" -#include "../World.h" -#include "../Blocks/BlockBed.h" +#include "Blocks/BlockBed.h" +#include "BlockEntities/BedEntity.h" @@ -22,35 +22,51 @@ public: } - virtual bool IsPlaceable(void) override - { - return true; - } - - - virtual bool GetBlocksToPlace( - cWorld & a_World, - cPlayer & a_Player, - const cItem & a_EquippedItem, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - sSetBlockVector & a_BlocksToPlace - ) override + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { const auto BlockMeta = cBlockBedHandler::YawToMetaData(a_Player.GetYaw()); - const auto HeadPosition = a_PlacedBlockPos + cBlockBedHandler::MetaDataToDirection(BlockMeta); + const auto HeadPosition = a_PlacePosition + cBlockBedHandler::MetaDataToDirection(BlockMeta); - // Vanilla only allows beds to be placed into air + auto & World = *a_Player.GetWorld(); + BLOCKTYPE HeadType; + NIBBLETYPE HeadMeta; + World.GetBlockTypeMeta(HeadPosition, HeadType, HeadMeta); + + // Vanilla only allows beds to be placed into air. // Check if there is empty space for the "head" block: - if (a_World.GetBlock(HeadPosition) != E_BLOCK_AIR) + if (!cBlockHandler::For(HeadType).DoesIgnoreBuildCollision(World, a_HeldItem, HeadPosition, HeadMeta, a_ClickedBlockFace, false)) { return false; } // The "foot", and the "head" block: - a_BlocksToPlace.emplace_back(a_PlacedBlockPos, E_BLOCK_BED, BlockMeta); - a_BlocksToPlace.emplace_back(HeadPosition, E_BLOCK_BED, BlockMeta | 0x08); + if ( + !a_Player.PlaceBlocks( + { + { a_PlacePosition, E_BLOCK_BED, BlockMeta }, + { HeadPosition, E_BLOCK_BED, static_cast(BlockMeta | 0x08) } + }) + ) + { + return false; + } + + auto SetColor = [&a_HeldItem](cBlockEntity & a_BlockEntity) + { + ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_BED); + + static_cast(a_BlockEntity).SetColor(a_HeldItem.m_ItemDamage); + return false; + }; + World.DoWithBlockEntityAt(a_PlacePosition, SetColor); + World.DoWithBlockEntityAt(HeadPosition, SetColor); + + return true; + } + + + virtual bool IsPlaceable(void) override + { return true; } }; diff --git a/src/Items/ItemBigFlower.h b/src/Items/ItemBigFlower.h index a67ca8d0a..12ebc2188 100644 --- a/src/Items/ItemBigFlower.h +++ b/src/Items/ItemBigFlower.h @@ -24,41 +24,29 @@ public: - virtual bool GetBlocksToPlace( - cWorld & a_World, - cPlayer & a_Player, - const cItem & a_EquippedItem, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - sSetBlockVector & a_BlocksToPlace - ) override + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { - // Can only be placed on dirt: - if ((a_PlacedBlockPos.y <= 0) || !IsBlockTypeOfDirt(a_World.GetBlock(a_PlacedBlockPos.addedY(-1)))) + // Needs at least two free blocks to build in: + if (a_PlacePosition.y >= (cChunkDef::Height - 1)) { return false; } - // Needs at least two free blocks to build in - if (a_PlacedBlockPos.y >= cChunkDef::Height - 1) - { - return false; - } - - auto TopPos = a_PlacedBlockPos.addedY(1); + const auto & World = *a_Player.GetWorld(); + const auto TopPos = a_PlacePosition.addedY(1); BLOCKTYPE TopType; NIBBLETYPE TopMeta; - a_World.GetBlockTypeMeta(TopPos, TopType, TopMeta); - cChunkInterface ChunkInterface(a_World.GetChunkMap()); + World.GetBlockTypeMeta(TopPos, TopType, TopMeta); - if (!cBlockHandler::For(TopType).DoesIgnoreBuildCollision(ChunkInterface, TopPos, a_Player, TopMeta)) + if (!cBlockHandler::For(TopType).DoesIgnoreBuildCollision(World, a_HeldItem, TopPos, TopMeta, a_ClickedBlockFace, false)) { return false; } - a_BlocksToPlace.emplace_back(a_PlacedBlockPos, E_BLOCK_BIG_FLOWER, a_EquippedItem.m_ItemDamage & 0x07); - a_BlocksToPlace.emplace_back(TopPos, E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP); - return true; + return a_Player.PlaceBlocks( + { + { a_PlacePosition, E_BLOCK_BIG_FLOWER, static_cast(a_HeldItem.m_ItemDamage & 0x07) }, + { TopPos, E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP } + }); } }; diff --git a/src/Items/ItemBucket.h b/src/Items/ItemBucket.h index a5b1085ba..6d7a33ccf 100644 --- a/src/Items/ItemBucket.h +++ b/src/Items/ItemBucket.h @@ -105,8 +105,8 @@ public: return false; } - // Remove water / lava block (unless plugins disagree) - if (!a_Player->PlaceBlock(BlockPos.x, BlockPos.y, BlockPos.z, E_BLOCK_AIR, 0)) + // Remove water / lava block (unless plugins disagree): + if (!a_Player->PlaceBlock(BlockPos, E_BLOCK_AIR, 0)) { return false; } @@ -175,7 +175,7 @@ public: } // Place the actual fluid block: - return a_Player->PlaceBlock(BlockPos.x, BlockPos.y, BlockPos.z, a_FluidBlock, 0); + return a_Player->PlaceBlock(BlockPos, a_FluidBlock, 0); } diff --git a/src/Items/ItemButton.h b/src/Items/ItemButton.h new file mode 100644 index 000000000..0f6e5c6f5 --- /dev/null +++ b/src/Items/ItemButton.h @@ -0,0 +1,45 @@ + +#pragma once + +#include "ItemHandler.h" + + + + + +class cItemButtonHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + /** Converts the block face of the neighbor to which the button is attached, to the block meta for this button. */ + static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace) + { + switch (a_BlockFace) + { + case BLOCK_FACE_YP: return 0x5; + case BLOCK_FACE_ZM: return 0x4; + case BLOCK_FACE_ZP: return 0x3; + case BLOCK_FACE_XM: return 0x2; + case BLOCK_FACE_XP: return 0x1; + case BLOCK_FACE_YM: return 0x0; + case BLOCK_FACE_NONE: + { + break; + } + } + UNREACHABLE("Unsupported block face"); + } + + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + return a_Player.PlaceBlock(a_PlacePosition, static_cast(a_HeldItem.m_ItemType), BlockFaceToMetaData(a_ClickedBlockFace)); + } +}; diff --git a/src/Items/ItemChest.h b/src/Items/ItemChest.h index 8548f8d25..a714045ee 100644 --- a/src/Items/ItemChest.h +++ b/src/Items/ItemChest.h @@ -2,8 +2,7 @@ #pragma once #include "ItemHandler.h" -#include "../BlockInfo.h" -#include "../Blocks/BlockChest.h" +#include "Blocks/BlockChest.h" @@ -21,59 +20,12 @@ public: { } + cItemChestHandler(const cItemChestHandler &) = delete; - /** We need an OnPlayerPlace override because we're processing neighbor chests and changing their metas, - the parent class cannot do that. */ - virtual bool OnPlayerPlace( - cWorld & a_World, - cPlayer & a_Player, - const cItem & a_EquippedItem, - const Vector3i a_ClickedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos - ) override - { - if (a_ClickedBlockFace < 0) - { - // Clicked in air - return false; - } - - if (!cChunkDef::IsValidHeight(a_ClickedBlockPos.y)) - { - // The clicked block is outside the world, ignore this call altogether (#128) - return false; - } - - // Check if the block ignores build collision (water, grass etc.): - BLOCKTYPE ClickedBlockType; - NIBBLETYPE ClickedBlockMeta; - a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta); - cChunkInterface ChunkInterface(a_World.GetChunkMap()); - Vector3i PlacePos; - if (cBlockHandler::For(ClickedBlockType).DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, a_Player, ClickedBlockMeta)) - { - PlacePos = a_ClickedBlockPos; - } - else - { - PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); - if (!cChunkDef::IsValidHeight(PlacePos.y)) - { - // The block is being placed outside the world, ignore this packet altogether (#128) - return false; - } - - // Check if the chest can overwrite the block at PlacePos: - BLOCKTYPE PlaceBlock; - NIBBLETYPE PlaceMeta; - a_World.GetBlockTypeMeta(PlacePos, PlaceBlock, PlaceMeta); - if (!cBlockHandler::For(PlaceBlock).DoesIgnoreBuildCollision(ChunkInterface, PlacePos, a_Player, PlaceMeta)) - { - return false; - } - } +private: + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { // Check that there is at most one single neighbor of the same chest type: static const Vector3i CrossCoords[] = { @@ -82,11 +34,14 @@ public: { 1, 0, 0}, { 0, 0, 1}, }; + + auto & World = *a_Player.GetWorld(); int NeighborIdx = -1; + for (size_t i = 0; i < ARRAYCOUNT(CrossCoords); i++) { - auto NeighborPos = PlacePos + CrossCoords[i]; - if (a_World.GetBlock(NeighborPos) != m_ItemType) + const auto NeighborPos = a_PlacePosition + CrossCoords[i]; + if (World.GetBlock(NeighborPos) != m_ItemType) { continue; } @@ -100,7 +55,7 @@ public: // Check that this neighbor is a single chest: for (size_t j = 0; j < ARRAYCOUNT(CrossCoords); j++) { - if (a_World.GetBlock(NeighborPos + CrossCoords[j]) == m_ItemType) + if (World.GetBlock(NeighborPos + CrossCoords[j]) == m_ItemType) { // Trying to place next to a dblchest return false; @@ -111,7 +66,7 @@ public: // Get the meta of the placed chest; take existing neighbors into account: BLOCKTYPE ChestBlockType = static_cast(m_ItemType); NIBBLETYPE Meta; - auto yaw = a_Player.GetYaw(); + const auto yaw = a_Player.GetYaw(); switch (NeighborIdx) { case 0: @@ -131,13 +86,13 @@ public: default: { // No neighbor, place based on yaw: - Meta = cBlockChestHandler::PlayerYawToMetaData(yaw); + Meta = cBlockChestHandler::YawToMetaData(yaw); break; } } // switch (NeighborIdx) // Place the new chest: - if (!a_Player.PlaceBlock(PlacePos.x, PlacePos.y, PlacePos.z, ChestBlockType, Meta)) + if (!a_Player.PlaceBlock(a_PlacePosition, ChestBlockType, Meta)) { return false; } @@ -145,17 +100,9 @@ public: // Adjust the existing chest, if any: if (NeighborIdx != -1) { - a_World.FastSetBlock(PlacePos + CrossCoords[NeighborIdx], ChestBlockType, Meta); + World.FastSetBlock(a_PlacePosition + CrossCoords[NeighborIdx], ChestBlockType, Meta); } - // Remove the "placed" item from inventory: - if (a_Player.IsGameModeSurvival()) - { - a_Player.GetInventory().RemoveOneEquippedItem(); - } return true; } - -private: - cItemChestHandler(const cItemChestHandler &) = delete; }; diff --git a/src/Items/ItemComparator.h b/src/Items/ItemComparator.h index fbb61b317..681ce0b54 100644 --- a/src/Items/ItemComparator.h +++ b/src/Items/ItemComparator.h @@ -24,25 +24,17 @@ public: - virtual bool IsPlaceable(void) override + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { - return true; + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_INACTIVE_COMPARATOR, cBlockComparatorHandler::YawToMetaData(a_Player.GetYaw())); } - virtual bool GetPlacementBlockTypeMeta( - cWorld * a_World, cPlayer * a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) override + virtual bool IsPlaceable(void) override { - a_BlockType = E_BLOCK_INACTIVE_COMPARATOR; - a_BlockMeta = cBlockComparatorHandler::YawToMetaData(a_Player->GetYaw()); return true; } } ; diff --git a/src/Items/ItemDoor.h b/src/Items/ItemDoor.h index aec6bc0fe..b85f018bc 100644 --- a/src/Items/ItemDoor.h +++ b/src/Items/ItemDoor.h @@ -25,13 +25,7 @@ public: - virtual bool GetBlocksToPlace( - cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - sSetBlockVector & a_BlocksToSet - ) override + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { // Vanilla only allows door placement while clicking on the top face of the block below the door: if (a_ClickedBlockFace != BLOCK_FACE_TOP) @@ -39,19 +33,6 @@ public: return false; } - // Door (bottom block) can be placed in Y range of [1, 254]: - if ((a_PlacedBlockPos.y < 1) || (a_PlacedBlockPos.y >= cChunkDef::Height - 2)) - { - return false; - } - - // The door needs a compatible block below it: - auto BelowPos = a_PlacedBlockPos.addedY(-1); - if (!cBlockDoorHandler::CanBeOn(a_World.GetBlock(BelowPos), a_World.GetBlockMeta(BelowPos))) - { - return false; - } - // Get the block type of the door to place: BLOCKTYPE BlockType; switch (m_ItemType) @@ -63,22 +44,22 @@ public: case E_ITEM_JUNGLE_DOOR: BlockType = E_BLOCK_JUNGLE_DOOR; break; case E_ITEM_DARK_OAK_DOOR: BlockType = E_BLOCK_DARK_OAK_DOOR; break; case E_ITEM_ACACIA_DOOR: BlockType = E_BLOCK_ACACIA_DOOR; break; - default: - { - ASSERT(!"Unhandled door type"); - return false; - } + default: UNREACHABLE("Unhandled door type"); } - // Check the two blocks that will get replaced by the door: - auto UpperBlockPos = a_PlacedBlockPos.addedY(1); - BLOCKTYPE LowerBlockType = a_World.GetBlock(a_PlacedBlockPos); - BLOCKTYPE UpperBlockType = a_World.GetBlock(UpperBlockPos); - if ( - !cBlockDoorHandler::CanReplaceBlock(LowerBlockType) || - !cBlockDoorHandler::CanReplaceBlock(UpperBlockType)) + const auto & World = *a_Player.GetWorld(); + const auto UpperBlockPosition = a_PlacePosition.addedY(1); + + // Check the block that will get replaced by the door: { - return false; + BLOCKTYPE TopType; + NIBBLETYPE TopMeta; + World.GetBlockTypeMeta(UpperBlockPosition, TopType, TopMeta); + + if (!cBlockHandler::For(TopType).DoesIgnoreBuildCollision(World, a_HeldItem, UpperBlockPosition, TopMeta, a_ClickedBlockFace, false)) + { + return false; + } } // Get the coords of the neighboring blocks: @@ -86,22 +67,24 @@ public: Vector3i RelDirToOutside = cBlockDoorHandler::GetRelativeDirectionToOutside(LowerBlockMeta); Vector3i LeftNeighborPos = RelDirToOutside; LeftNeighborPos.TurnCW(); - LeftNeighborPos.Move(a_PlacedBlockPos); + LeftNeighborPos.Move(a_PlacePosition); Vector3i RightNeighborPos = RelDirToOutside; RightNeighborPos.TurnCCW(); - RightNeighborPos.Move(a_PlacedBlockPos); + RightNeighborPos.Move(a_PlacePosition); // Decide whether the hinge is on the left (default) or on the right: NIBBLETYPE UpperBlockMeta = 0x08; - BLOCKTYPE LeftNeighborBlock = a_World.GetBlock(LeftNeighborPos); - BLOCKTYPE RightNeighborBlock = a_World.GetBlock(RightNeighborPos); + BLOCKTYPE LeftNeighborBlock = World.GetBlock(LeftNeighborPos); + BLOCKTYPE RightNeighborBlock = World.GetBlock(RightNeighborPos); + /* // DEBUG: - FLOGD("Door being placed at {0}", a_PlacedBlockPos); + FLOGD("Door being placed at {0}", a_PlacePosition); FLOGD("RelDirToOutside: {0}", RelDirToOutside); FLOGD("Left neighbor at {0}: {1} ({2})", LeftNeighborPos, LeftNeighborBlock, ItemTypeToString(LeftNeighborBlock)); FLOGD("Right neighbor at {0}: {1} ({2})", RightNeighborPos, RightNeighborBlock, ItemTypeToString(RightNeighborBlock)); */ + if ( cBlockDoorHandler::IsDoorBlockType(LeftNeighborBlock) || // The block to the left is a door block ( @@ -116,9 +99,11 @@ public: } // Set the blocks: - a_BlocksToSet.emplace_back(a_PlacedBlockPos, BlockType, LowerBlockMeta); - a_BlocksToSet.emplace_back(UpperBlockPos, BlockType, UpperBlockMeta); - return true; + return a_Player.PlaceBlocks( + { + { a_PlacePosition, BlockType, LowerBlockMeta }, + { UpperBlockPosition, BlockType, UpperBlockMeta } + }); } diff --git a/src/Items/ItemDropSpenser.h b/src/Items/ItemDropSpenser.h new file mode 100644 index 000000000..d226436db --- /dev/null +++ b/src/Items/ItemDropSpenser.h @@ -0,0 +1,26 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockDropSpenser.h" + + + + + +class cItemDropSpenserHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + return a_Player.PlaceBlock(a_PlacePosition, static_cast(a_HeldItem.m_ItemType), cBlockDropSpenserHandler::PitchYawToMetaData(a_Player.GetYaw(), a_Player.GetPitch())); + } +}; diff --git a/src/Items/ItemDye.h b/src/Items/ItemDye.h index 631e28e7d..683e8a73f 100644 --- a/src/Items/ItemDye.h +++ b/src/Items/ItemDye.h @@ -74,7 +74,7 @@ public: { return false; } - if (a_Player->PlaceBlock(CocoaPos.x, CocoaPos.y, CocoaPos.z, E_BLOCK_COCOA_POD, BlockMeta)) + if (a_Player->PlaceBlock(CocoaPos, E_BLOCK_COCOA_POD, BlockMeta)) { if (a_Player->IsGameModeSurvival()) { diff --git a/src/Items/ItemEnchantingTable.h b/src/Items/ItemEnchantingTable.h index 12835cb4a..29a6eeef6 100644 --- a/src/Items/ItemEnchantingTable.h +++ b/src/Items/ItemEnchantingTable.h @@ -20,40 +20,32 @@ public: private: - virtual bool IsPlaceable(void) override - { - return true; - } - - - virtual bool OnPlayerPlace( - cWorld & a_World, - cPlayer & a_Player, - const cItem & a_EquippedItem, - const Vector3i a_ClickedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos - ) override + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { - if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos)) + if (!Super::CommitPlacement(a_Player, a_HeldItem, a_PlacePosition, a_ClickedBlockFace, a_CursorPosition)) { return false; } - if (a_EquippedItem.IsCustomNameEmpty()) + if (a_HeldItem.IsCustomNameEmpty()) { return true; } - const auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); - a_World.DoWithBlockEntityAt(PlacePos, [&a_EquippedItem](cBlockEntity & a_Entity) + a_Player.GetWorld()->DoWithBlockEntityAt(a_PlacePosition, [&a_HeldItem](cBlockEntity & a_BlockEntity) { - ASSERT(a_Entity.GetBlockType() == E_BLOCK_ENCHANTMENT_TABLE); + ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_ENCHANTMENT_TABLE); - static_cast(a_Entity).SetCustomName(a_EquippedItem.m_CustomName); + static_cast(a_BlockEntity).SetCustomName(a_HeldItem.m_CustomName); return false; }); return true; } + + + virtual bool IsPlaceable(void) override + { + return true; + } } ; diff --git a/src/Items/ItemEndPortalFrame.h b/src/Items/ItemEndPortalFrame.h new file mode 100644 index 000000000..08bcdf9fa --- /dev/null +++ b/src/Items/ItemEndPortalFrame.h @@ -0,0 +1,26 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockEndPortalFrame.h" + + + + + +class cItemEndPortalFrameHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_END_PORTAL_FRAME, cBlockEndPortalFrameHandler::YawToMetaData(a_Player.GetYaw())); + } +}; diff --git a/src/Items/ItemEnderchest.h b/src/Items/ItemEnderchest.h new file mode 100644 index 000000000..4feba1f13 --- /dev/null +++ b/src/Items/ItemEnderchest.h @@ -0,0 +1,26 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockEnderchest.h" + + + + + +class cItemEnderchestHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_ENDER_CHEST, cBlockEnderchestHandler::YawToMetaData(a_Player.GetYaw())); + } +}; diff --git a/src/Items/ItemFenceGate.h b/src/Items/ItemFenceGate.h new file mode 100644 index 000000000..cd06340b0 --- /dev/null +++ b/src/Items/ItemFenceGate.h @@ -0,0 +1,26 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockFenceGate.h" + + + + + +class cItemFenceGateHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + return a_Player.PlaceBlock(a_PlacePosition, static_cast(a_HeldItem.m_ItemType), cBlockFenceGateHandler::YawToMetaData(a_Player.GetYaw())); + } +}; diff --git a/src/Items/ItemFurnace.h b/src/Items/ItemFurnace.h new file mode 100644 index 000000000..24bcd5e06 --- /dev/null +++ b/src/Items/ItemFurnace.h @@ -0,0 +1,26 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockFurnace.h" + + + + + +class cItemFurnaceHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_FURNACE, cBlockFurnaceHandler::YawToMetaData(a_Player.GetYaw())); + } +}; diff --git a/src/Items/ItemGlazedTerracotta.h b/src/Items/ItemGlazedTerracotta.h new file mode 100644 index 000000000..d08d6308e --- /dev/null +++ b/src/Items/ItemGlazedTerracotta.h @@ -0,0 +1,26 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockGlazedTerracotta.h" + + + + + +class cItemGlazedTerracottaHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + return a_Player.PlaceBlock(a_PlacePosition, static_cast(a_HeldItem.m_ItemType), cBlockGlazedTerracottaHandler::YawToMetaData(a_Player.GetYaw())); + } +}; diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index bfeba1373..1c6300353 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -8,6 +8,7 @@ #include "../Chunk.h" // Handlers: +#include "ItemAnvil.h" #include "ItemArmor.h" #include "ItemAxe.h" #include "ItemBanner.h" @@ -17,23 +18,34 @@ #include "ItemBottle.h" #include "ItemBow.h" #include "ItemBucket.h" +#include "ItemButton.h" #include "ItemChest.h" #include "ItemCloth.h" #include "ItemComparator.h" #include "ItemCookedFish.h" #include "ItemDoor.h" +#include "ItemDropSpenser.h" #include "ItemDye.h" #include "ItemEmptyMap.h" #include "ItemEnchantingTable.h" #include "ItemEndCrystal.h" +#include "ItemEnderchest.h" +#include "ItemEndPortalFrame.h" #include "ItemEyeOfEnder.h" +#include "ItemFenceGate.h" #include "ItemFishingRod.h" #include "ItemFood.h" #include "ItemFoodSeeds.h" +#include "ItemFurnace.h" +#include "ItemGlazedTerracotta.h" #include "ItemGoldenApple.h" #include "ItemHoe.h" +#include "ItemHopper.h" #include "ItemItemFrame.h" +#include "ItemJackOLantern.h" +#include "ItemLadder.h" #include "ItemLeaves.h" +#include "ItemLever.h" #include "ItemLighter.h" #include "ItemLilypad.h" #include "ItemMap.h" @@ -41,11 +53,16 @@ #include "ItemMinecart.h" #include "ItemMobHead.h" #include "ItemNetherWart.h" +#include "ItemObserver.h" #include "ItemPainting.h" #include "ItemPickaxe.h" +#include "ItemPiston.h" +#include "ItemPlanks.h" #include "ItemPoisonousPotato.h" #include "ItemPotion.h" #include "ItemPumpkin.h" +#include "ItemQuartz.h" +#include "ItemRail.h" #include "ItemRawChicken.h" #include "ItemRawFish.h" #include "ItemRedstoneDust.h" @@ -55,13 +72,20 @@ #include "ItemSeeds.h" #include "ItemShears.h" #include "ItemShovel.h" +#include "ItemSideways.h" #include "ItemSign.h" #include "ItemSlab.h" +#include "ItemSnow.h" #include "ItemSoup.h" #include "ItemSpawnEgg.h" #include "ItemSpiderEye.h" +#include "ItemStairs.h" #include "ItemSword.h" #include "ItemThrowable.h" +#include "ItemTorch.h" +#include "ItemTrapdoor.h" +#include "ItemTripwireHook.h" +#include "ItemVine.h" #include "../Blocks/BlockHandler.h" #include "SimplePlaceableItemHandler.h" @@ -113,56 +137,87 @@ cItemHandler * cItemHandler::CreateItemHandler(int a_ItemType) default: return new cItemHandler(a_ItemType); // Single item per handler, alphabetically sorted: - case E_ITEM_BANNER: return new cItemBannerHandler(a_ItemType); - case E_BLOCK_BIG_FLOWER: return new cItemBigFlowerHandler; - case E_BLOCK_CHEST: return new cItemChestHandler(a_ItemType); - case E_BLOCK_ENCHANTMENT_TABLE: return new cItemEnchantingTableHandler(a_ItemType); - case E_BLOCK_LEAVES: return new cItemLeavesHandler(a_ItemType); - case E_BLOCK_LILY_PAD: return new cItemLilypadHandler(a_ItemType); - case E_BLOCK_HEAD: return new cItemMobHeadHandler(a_ItemType); - case E_BLOCK_NEW_LEAVES: return new cItemLeavesHandler(a_ItemType); - case E_BLOCK_PUMPKIN: return new cItemPumpkinHandler; - case E_BLOCK_PURPUR_SLAB: return new cItemSlabHandler(E_BLOCK_PURPUR_SLAB, E_BLOCK_PURPUR_DOUBLE_SLAB); - case E_BLOCK_RED_SANDSTONE_SLAB: return new cItemSlabHandler(E_BLOCK_RED_SANDSTONE_SLAB, E_BLOCK_DOUBLE_RED_SANDSTONE_SLAB); - case E_BLOCK_SAPLING: return new cItemSaplingHandler(a_ItemType); - case E_BLOCK_STONE_SLAB: return new cItemSlabHandler(E_BLOCK_STONE_SLAB, E_BLOCK_DOUBLE_STONE_SLAB); - case E_BLOCK_TRAPPED_CHEST: return new cItemChestHandler(a_ItemType); - case E_BLOCK_WOODEN_SLAB: return new cItemSlabHandler(E_BLOCK_WOODEN_SLAB, E_BLOCK_DOUBLE_WOODEN_SLAB); - case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType); - case E_ITEM_BED: return new cItemBedHandler(a_ItemType); - case E_ITEM_BOTTLE_O_ENCHANTING: return new cItemBottleOEnchantingHandler(); - case E_ITEM_BOW: return new cItemBowHandler(); - case E_ITEM_BREWING_STAND: return new cSimplePlaceableItemHandler(a_ItemType, E_BLOCK_BREWING_STAND); - case E_ITEM_CAKE: return new cSimplePlaceableItemHandler(a_ItemType, E_BLOCK_CAKE); - case E_ITEM_CAULDRON: return new cSimplePlaceableItemHandler(a_ItemType, E_BLOCK_CAULDRON); - case E_ITEM_COMPARATOR: return new cItemComparatorHandler(a_ItemType); - case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType); - case E_ITEM_EGG: return new cItemEggHandler(); - case E_ITEM_EMPTY_MAP: return new cItemEmptyMapHandler(); - case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler(); - case E_ITEM_END_CRYSTAL: return new cItemEndCrystalHandler(a_ItemType); - case E_ITEM_EYE_OF_ENDER: return new cItemEyeOfEnderHandler(); - case E_ITEM_FIRE_CHARGE: return new cItemLighterHandler(a_ItemType); - case E_ITEM_FIREWORK_ROCKET: return new cItemFireworkHandler(); - case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType); - case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType); - case E_ITEM_FLOWER_POT: return new cSimplePlaceableItemHandler(a_ItemType, E_BLOCK_FLOWER_POT); - case E_ITEM_GLASS_BOTTLE: return new cItemBottleHandler(); - case E_ITEM_MAP: return new cItemMapHandler(); - case E_ITEM_MILK: return new cItemMilkHandler(); - case E_ITEM_ITEM_FRAME: return new cItemItemFrameHandler(a_ItemType); - case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType); - case E_ITEM_PAINTING: return new cItemPaintingHandler(a_ItemType); - case E_ITEM_POTIONS: return new cItemPotionHandler(); - case E_ITEM_REDSTONE_DUST: return new cItemRedstoneDustHandler(a_ItemType); - case E_ITEM_REDSTONE_REPEATER: return new cItemRedstoneRepeaterHandler(a_ItemType); - case E_ITEM_SHEARS: return new cItemShearsHandler(a_ItemType); - case E_ITEM_SIGN: return new cItemSignHandler(a_ItemType); - case E_ITEM_HEAD: return new cItemMobHeadHandler(a_ItemType); - case E_ITEM_SNOWBALL: return new cItemSnowballHandler(); - case E_ITEM_SPAWN_EGG: return new cItemSpawnEggHandler(a_ItemType); - case E_ITEM_STRING: return new cSimplePlaceableItemHandler(a_ItemType, E_BLOCK_TRIPWIRE); - case E_ITEM_SUGARCANE: return new cSimplePlaceableItemHandler(a_ItemType, E_BLOCK_SUGARCANE); + case E_BLOCK_ACTIVATOR_RAIL: return new cItemRailHandler(a_ItemType); + case E_BLOCK_ANVIL: return new cItemAnvilHandler(a_ItemType); + case E_BLOCK_BIG_FLOWER: return new cItemBigFlowerHandler; + case E_BLOCK_CHEST: return new cItemChestHandler(a_ItemType); + case E_BLOCK_DETECTOR_RAIL: return new cItemRailHandler(a_ItemType); + case E_BLOCK_DISPENSER: return new cItemDropSpenserHandler(a_ItemType); + case E_BLOCK_DROPPER: return new cItemDropSpenserHandler(a_ItemType); + case E_BLOCK_ENCHANTMENT_TABLE: return new cItemEnchantingTableHandler(a_ItemType); + case E_BLOCK_ENDER_CHEST: return new cItemEnderchestHandler(a_ItemType); + case E_BLOCK_END_PORTAL_FRAME: return new cItemEndPortalFrameHandler(a_ItemType); + case E_BLOCK_FURNACE: return new cItemFurnaceHandler(a_ItemType); + case E_BLOCK_HAY_BALE: return new cItemSidewaysHandler(a_ItemType); + case E_BLOCK_HEAD: return new cItemMobHeadHandler(a_ItemType); + case E_BLOCK_HOPPER: return new cItemHopperHandler(a_ItemType); + case E_BLOCK_IRON_TRAPDOOR: return new cItemTrapdoorHandler(a_ItemType); + case E_BLOCK_JACK_O_LANTERN: return new cItemJackOLanternHandler(a_ItemType); + case E_BLOCK_LADDER: return new cItemLadderHandler(a_ItemType); + case E_BLOCK_LEAVES: return new cItemLeavesHandler(a_ItemType); + case E_BLOCK_LEVER: return new cItemLeverHandler(a_ItemType); + case E_BLOCK_LILY_PAD: return new cItemLilypadHandler(a_ItemType); + case E_BLOCK_LOG: return new cItemSidewaysHandler(a_ItemType); + case E_BLOCK_NEW_LEAVES: return new cItemLeavesHandler(a_ItemType); + case E_BLOCK_NEW_LOG: return new cItemSidewaysHandler(a_ItemType); + case E_BLOCK_OBSERVER: return new cItemObserverHandler(a_ItemType); + case E_BLOCK_PISTON: return new cItemPistonHandler(a_ItemType); + case E_BLOCK_PLANKS: return new cItemPlanksHandler(a_ItemType); + case E_BLOCK_POWERED_RAIL: return new cItemRailHandler(a_ItemType); + case E_BLOCK_PUMPKIN: return new cItemPumpkinHandler(a_ItemType); + case E_BLOCK_PURPUR_SLAB: return new cItemSlabHandler(a_ItemType); + case E_BLOCK_QUARTZ_BLOCK: return new cItemQuartzHandler(a_ItemType); + case E_BLOCK_RAIL: return new cItemRailHandler(a_ItemType); + case E_BLOCK_REDSTONE_TORCH_ON: return new cItemTorchHandler(a_ItemType); + case E_BLOCK_RED_SANDSTONE_SLAB: return new cItemSlabHandler(a_ItemType); + case E_BLOCK_SAPLING: return new cItemSaplingHandler(a_ItemType); + case E_BLOCK_SNOW: return new cItemSnowHandler(a_ItemType); + case E_BLOCK_STICKY_PISTON: return new cItemPistonHandler(a_ItemType); + case E_BLOCK_STONE_BUTTON: return new cItemButtonHandler(a_ItemType); + case E_BLOCK_STONE_SLAB: return new cItemSlabHandler(a_ItemType); + case E_BLOCK_TORCH: return new cItemTorchHandler(a_ItemType); + case E_BLOCK_TRAPDOOR: return new cItemTrapdoorHandler(a_ItemType); + case E_BLOCK_TRAPPED_CHEST: return new cItemChestHandler(a_ItemType); + case E_BLOCK_TRIPWIRE_HOOK: return new cItemTripwireHookHandler(a_ItemType); + case E_BLOCK_VINES: return new cItemVineHandler(a_ItemType); + case E_BLOCK_WOODEN_BUTTON: return new cItemButtonHandler(a_ItemType); + case E_BLOCK_WOODEN_SLAB: return new cItemSlabHandler(a_ItemType); + case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType); + case E_ITEM_BANNER: return new cItemBannerHandler(a_ItemType); + case E_ITEM_BED: return new cItemBedHandler(a_ItemType); + case E_ITEM_BOTTLE_O_ENCHANTING: return new cItemBottleOEnchantingHandler(); + case E_ITEM_BOW: return new cItemBowHandler(); + case E_ITEM_BREWING_STAND: return new cSimplePlaceableItemHandler(a_ItemType, E_BLOCK_BREWING_STAND); + case E_ITEM_CAKE: return new cSimplePlaceableItemHandler(a_ItemType, E_BLOCK_CAKE); + case E_ITEM_CAULDRON: return new cSimplePlaceableItemHandler(a_ItemType, E_BLOCK_CAULDRON); + case E_ITEM_COMPARATOR: return new cItemComparatorHandler(a_ItemType); + case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType); + case E_ITEM_EGG: return new cItemEggHandler(); + case E_ITEM_EMPTY_MAP: return new cItemEmptyMapHandler(); + case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler(); + case E_ITEM_END_CRYSTAL: return new cItemEndCrystalHandler(a_ItemType); + case E_ITEM_EYE_OF_ENDER: return new cItemEyeOfEnderHandler(); + case E_ITEM_FIREWORK_ROCKET: return new cItemFireworkHandler(); + case E_ITEM_FIRE_CHARGE: return new cItemLighterHandler(a_ItemType); + case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType); + case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType); + case E_ITEM_FLOWER_POT: return new cSimplePlaceableItemHandler(a_ItemType, E_BLOCK_FLOWER_POT); + case E_ITEM_GLASS_BOTTLE: return new cItemBottleHandler(); + case E_ITEM_HEAD: return new cItemMobHeadHandler(a_ItemType); + case E_ITEM_ITEM_FRAME: return new cItemItemFrameHandler(a_ItemType); + case E_ITEM_MAP: return new cItemMapHandler(); + case E_ITEM_MILK: return new cItemMilkHandler(); + case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType); + case E_ITEM_PAINTING: return new cItemPaintingHandler(a_ItemType); + case E_ITEM_POTIONS: return new cItemPotionHandler(); + case E_ITEM_REDSTONE_DUST: return new cItemRedstoneDustHandler(a_ItemType); + case E_ITEM_REDSTONE_REPEATER: return new cItemRedstoneRepeaterHandler(a_ItemType); + case E_ITEM_SHEARS: return new cItemShearsHandler(a_ItemType); + case E_ITEM_SIGN: return new cItemSignHandler(a_ItemType); + case E_ITEM_SNOWBALL: return new cItemSnowballHandler(); + case E_ITEM_SPAWN_EGG: return new cItemSpawnEggHandler(a_ItemType); + case E_ITEM_STRING: return new cSimplePlaceableItemHandler(a_ItemType, E_BLOCK_TRIPWIRE); + case E_ITEM_SUGARCANE: return new cSimplePlaceableItemHandler(a_ItemType, E_BLOCK_SUGARCANE); case E_ITEM_WOODEN_HOE: case E_ITEM_STONE_HOE: @@ -247,6 +302,54 @@ cItemHandler * cItemHandler::CreateItemHandler(int a_ItemType) return new cItemMinecartHandler(a_ItemType); } + case E_BLOCK_ACACIA_FENCE_GATE: + case E_BLOCK_BIRCH_FENCE_GATE: + case E_BLOCK_DARK_OAK_FENCE_GATE: + case E_BLOCK_JUNGLE_FENCE_GATE: + case E_BLOCK_OAK_FENCE_GATE: + case E_BLOCK_SPRUCE_FENCE_GATE: + { + return new cItemFenceGateHandler(a_ItemType); + } + + case E_BLOCK_ACACIA_WOOD_STAIRS: + case E_BLOCK_BIRCH_WOOD_STAIRS: + case E_BLOCK_BRICK_STAIRS: + case E_BLOCK_COBBLESTONE_STAIRS: + case E_BLOCK_DARK_OAK_WOOD_STAIRS: + case E_BLOCK_JUNGLE_WOOD_STAIRS: + case E_BLOCK_NETHER_BRICK_STAIRS: + case E_BLOCK_OAK_WOOD_STAIRS: + case E_BLOCK_PURPUR_STAIRS: + case E_BLOCK_QUARTZ_STAIRS: + case E_BLOCK_RED_SANDSTONE_STAIRS: + case E_BLOCK_SANDSTONE_STAIRS: + case E_BLOCK_SPRUCE_WOOD_STAIRS: + case E_BLOCK_STONE_BRICK_STAIRS: + { + return new cItemStairsHandler(a_ItemType); + } + + case E_BLOCK_WHITE_GLAZED_TERRACOTTA: + case E_BLOCK_ORANGE_GLAZED_TERRACOTTA: + case E_BLOCK_MAGENTA_GLAZED_TERRACOTTA: + case E_BLOCK_LIGHT_BLUE_GLAZED_TERRACOTTA: + case E_BLOCK_YELLOW_GLAZED_TERRACOTTA: + case E_BLOCK_LIME_GLAZED_TERRACOTTA: + case E_BLOCK_PINK_GLAZED_TERRACOTTA: + case E_BLOCK_GRAY_GLAZED_TERRACOTTA: + case E_BLOCK_LIGHT_GRAY_GLAZED_TERRACOTTA: + case E_BLOCK_CYAN_GLAZED_TERRACOTTA: + case E_BLOCK_PURPLE_GLAZED_TERRACOTTA: + case E_BLOCK_BLUE_GLAZED_TERRACOTTA: + case E_BLOCK_BROWN_GLAZED_TERRACOTTA: + case E_BLOCK_GREEN_GLAZED_TERRACOTTA: + case E_BLOCK_RED_GLAZED_TERRACOTTA: + case E_BLOCK_BLACK_GLAZED_TERRACOTTA: + { + return new cItemGlazedTerracottaHandler(a_ItemType); + } + // Food (please keep alpha-sorted): case E_ITEM_BAKED_POTATO: return new cItemFoodHandler(a_ItemType, FoodInfo(5, 6)); case E_ITEM_BEETROOT: return new cItemFoodHandler(a_ItemType, FoodInfo(1, 1.2)); @@ -347,84 +450,66 @@ cItemHandler::cItemHandler(int a_ItemType) -bool cItemHandler::OnPlayerPlace( - cWorld & a_World, - cPlayer & a_Player, - const cItem & a_EquippedItem, - const Vector3i a_ClickedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos -) +void cItemHandler::OnPlayerPlace(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_ClickedBlockPosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) { if (a_ClickedBlockFace == BLOCK_FACE_NONE) { // Clicked in the air, no placement possible - return false; + return; } - if (!cChunkDef::IsValidHeight(a_ClickedBlockPos.y)) + if (!cChunkDef::IsValidHeight(a_ClickedBlockPosition.y)) { - // The clicked block is outside the world, ignore this call altogether (#128) - return false; + // The clicked block is outside the world, ignore this call altogether (GH #128): + return; } + const auto & World = *a_Player.GetWorld(); BLOCKTYPE ClickedBlockType; NIBBLETYPE ClickedBlockMeta; - - a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta); - cChunkInterface ChunkInterface(a_World.GetChunkMap()); + World.GetBlockTypeMeta(a_ClickedBlockPosition, ClickedBlockType, ClickedBlockMeta); // Check if the block ignores build collision (water, grass etc.): - auto PlacedBlockPos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); - if (cBlockHandler::For(ClickedBlockType).DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, a_Player, ClickedBlockMeta)) + if (cBlockHandler::For(ClickedBlockType).DoesIgnoreBuildCollision(World, a_HeldItem, a_ClickedBlockPosition, ClickedBlockMeta, a_ClickedBlockFace, true)) { - // Replace the clicked block: - a_World.DropBlockAsPickups(a_ClickedBlockPos, &a_Player, nullptr); - PlacedBlockPos = a_ClickedBlockPos; + // Try to place the block at the clicked position: + if (!CommitPlacement(a_Player, a_HeldItem, a_ClickedBlockPosition, a_ClickedBlockFace, a_CursorPosition)) + { + // The placement failed, the blocks have already been re-sent, re-send inventory: + a_Player.GetInventory().SendEquippedSlot(); + return; + } } else { - if (!cChunkDef::IsValidHeight(PlacedBlockPos.y)) + const auto PlacedPosition = AddFaceDirection(a_ClickedBlockPosition, a_ClickedBlockFace); + + if (!cChunkDef::IsValidHeight(PlacedPosition.y)) { - // The block is being placed outside the world, ignore this packet altogether (#128) - return false; + // The block is being placed outside the world, ignore this packet altogether (GH #128): + return; } NIBBLETYPE PlaceMeta; BLOCKTYPE PlaceBlock; - a_World.GetBlockTypeMeta(PlacedBlockPos, PlaceBlock, PlaceMeta); + World.GetBlockTypeMeta(PlacedPosition, PlaceBlock, PlaceMeta); // Clicked on side of block, make sure that placement won't be cancelled if there is a slab able to be double slabbed. // No need to do combinability (dblslab) checks, client will do that here. - if (!cBlockHandler::For(PlaceBlock).DoesIgnoreBuildCollision(ChunkInterface, PlacedBlockPos, a_Player, PlaceMeta)) + if (!cBlockHandler::For(PlaceBlock).DoesIgnoreBuildCollision(World, a_HeldItem, PlacedPosition, PlaceMeta, a_ClickedBlockFace, false)) { // Tried to place a block into another? // Happens when you place a block aiming at side of block with a torch on it or stem beside it - return false; + return; } - } - // Get all the blocks to place: - sSetBlockVector blocks; - if (!GetBlocksToPlace(a_World, a_Player, a_EquippedItem, PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, blocks)) - { - // Handler refused the placement, send that information back to the client: - for (const auto & blk: blocks) + // Try to place the block: + if (!CommitPlacement(a_Player, a_HeldItem, PlacedPosition, a_ClickedBlockFace, a_CursorPosition)) { - const auto & AbsPos = blk.GetAbsolutePos(); - a_World.SendBlockTo(AbsPos, a_Player); + // The placement failed, the blocks have already been re-sent, re-send inventory: + a_Player.GetInventory().SendEquippedSlot(); + return; } - a_World.SendBlockTo(PlacedBlockPos, a_Player); - a_Player.GetInventory().SendEquippedSlot(); - return false; - } - - // Try to place the blocks: - if (!a_Player.PlaceBlocks(blocks)) - { - // The placement failed, the blocks have already been re-sent, re-send inventory: - a_Player.GetInventory().SendEquippedSlot(); - return false; } // Remove the "placed" item: @@ -432,29 +517,6 @@ bool cItemHandler::OnPlayerPlace( { a_Player.GetInventory().RemoveOneEquippedItem(); } - return true; -} - - - - - -bool cItemHandler::GetBlocksToPlace( - cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - sSetBlockVector & a_BlocksToSet -) -{ - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - if (!GetPlacementBlockTypeMeta(&a_World, &a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, BlockType, BlockMeta)) - { - return false; - } - a_BlocksToSet.emplace_back(a_PlacedBlockPos, BlockType, BlockMeta); - return true; } @@ -821,34 +883,6 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType) -bool cItemHandler::GetPlacementBlockTypeMeta( - cWorld * a_World, cPlayer * a_Player, - const Vector3i a_PlacedBlockPos, eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta -) -{ - ASSERT(m_ItemType < 256); // Items with IDs above 255 should all be handled by specific handlers - - if (m_ItemType >= 256) - { - LOGERROR("%s: Item %d is not eligible for direct block placement!", __FUNCTION__, m_ItemType); - return false; - } - - cChunkInterface ChunkInterface(a_World->GetChunkMap()); - return cBlockHandler::For(static_cast(m_ItemType)).GetPlacementBlockTypeMeta( - ChunkInterface, *a_Player, - a_PlacedBlockPos, a_ClickedBlockFace, - a_CursorPos, - a_BlockType, a_BlockMeta - ); -} - - - - - bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item) { auto FoodInfo = GetFoodInfo(a_Item); @@ -873,3 +907,19 @@ float cItemHandler::GetBlockBreakingStrength(BLOCKTYPE a_Block) { return 1.0f; } + + + + + +bool cItemHandler::CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) +{ + ASSERT(m_ItemType < 256); // Items with IDs above 255 should all be handled by specific handlers. + + // By default, all blocks can be placed and the meta is copied over from the item's damage value: + return a_Player.PlaceBlock( + a_PlacePosition, + static_cast(m_ItemType), + static_cast(a_HeldItem.m_ItemDamage & 0x0f) + ); +} diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index 74de4eaa5..415f7f24f 100644 --- a/src/Items/ItemHandler.h +++ b/src/Items/ItemHandler.h @@ -9,6 +9,7 @@ // fwd: +class cChunk; class cWorld; class cPlayer; class cBlockPluginInterface; @@ -36,55 +37,14 @@ public: /** Force virtual destructor */ virtual ~cItemHandler() {} - /** Called when the player tries to place the item (right mouse button, IsPlaceable() == true). a_ClickedBlockPos is the (neighbor) block that has been clicked to place this item. a_ClickedBlockFace is the face of the neighbor that has been clicked to place this item. a_CursorPos is the position of the player's cursor within a_ClickedBlockFace. The default handler uses GetBlocksToPlace() and places the returned blocks. Override if the item needs advanced processing, such as spawning a mob based on the blocks being placed. - If the block placement is refused inside this call, it will automatically revert the client-side changes. - Returns true if the placement succeeded, false if the placement was aborted for any reason. */ - virtual bool OnPlayerPlace( - cWorld & a_World, - cPlayer & a_Player, - const cItem & a_EquippedItem, - const Vector3i a_ClickedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos - ); - - - /** Called from OnPlayerPlace() to determine the blocks that the current placement operation should set. - a_PlacedBlockPos points to the location where the new block should be set. - a_ClickedBlockFace is the block face of the neighbor that was clicked to place this block. - a_CursorPos is the position of the mouse cursor within the clicked (neighbor's) block face. - The blocks in a_BlocksToPlace will be sent through cPlayer::PlaceBlocks() after returning from this function. - The default handler uses GetPlacementBlockTypeMeta() and provides that as the single block at the specified coords. - Returns true if the placement succeeded, false if the placement was aborted for any reason. - If aborted, the server then sends all original blocks in the coords provided in a_BlocksToSet to the client. */ - virtual bool GetBlocksToPlace( - cWorld & a_World, - cPlayer & a_Player, - const cItem & a_EquippedItem, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - sSetBlockVector & a_BlocksToPlace - ); - - - /** Called when the player right-clicks with this item and IsPlaceable() == true, and OnPlayerPlace() is not overridden. - This function should provide the block type and meta for the placed block, or refuse the placement. - Returns true to allow placement, false to refuse. */ - virtual bool GetPlacementBlockTypeMeta( - cWorld * a_World, cPlayer * a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ); - + If the block placement is refused inside this call, it will automatically revert the client-side changes. */ + void OnPlayerPlace(cPlayer & a_Player, const cItem & a_HeldItem, Vector3i a_ClickedBlockPosition, eBlockFace a_ClickedBlockFace, Vector3i a_CursorPosition); /** Called when the player tries to use the item (right mouse button). Descendants can return false to abort the usage (default behavior). */ @@ -97,7 +57,6 @@ public: eBlockFace a_ClickedBlockFace ); - /** Called when the client sends the SHOOT status in the lclk packet (releasing the bow). */ virtual void OnItemShoot(cPlayer *, const Vector3i a_BlockPos, eBlockFace a_BlockFace) { @@ -181,9 +140,16 @@ public: static void Deinit(); protected: + int m_ItemType; static cItemHandler * CreateItemHandler(int m_ItemType); + /** Performs the actual placement of this placeable item. + The descendant handler should call a_Player.PlaceBlock(s) supplying correct values for the newly placed block. + The default handler uses the stored block type and meta copied from the lowest 4 bits of the player's equipped item's damage value. + Handlers return what a_Player.PlaceBlock(s) returns, indicating whether the placement was successful. */ + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, Vector3i a_PlacePosition, eBlockFace a_ClickedBlockFace, Vector3i a_CursorPosition); + static cItemHandler * m_ItemHandler[E_ITEM_LAST + 1]; static bool m_HandlerInitialized; // used to detect if the itemhandlers are initialized }; diff --git a/src/Items/ItemHopper.h b/src/Items/ItemHopper.h new file mode 100644 index 000000000..2f0651a43 --- /dev/null +++ b/src/Items/ItemHopper.h @@ -0,0 +1,40 @@ + +#pragma once + +#include "ItemHandler.h" + + + + + +class cItemHopperHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace) + { + switch (a_BlockFace) + { + case BLOCK_FACE_BOTTOM: return E_META_HOPPER_FACING_YM; + case BLOCK_FACE_TOP: return E_META_HOPPER_FACING_YM; + case BLOCK_FACE_EAST: return E_META_HOPPER_FACING_XM; + case BLOCK_FACE_NORTH: return E_META_HOPPER_FACING_ZP; + case BLOCK_FACE_SOUTH: return E_META_HOPPER_FACING_ZM; + case BLOCK_FACE_WEST: return E_META_HOPPER_FACING_XP; + default: UNREACHABLE("Unsupported block face"); + } + } + + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_HOPPER, BlockFaceToMetaData(a_ClickedBlockFace)); + } +}; diff --git a/src/Items/ItemJackOLantern.h b/src/Items/ItemJackOLantern.h new file mode 100644 index 000000000..703088013 --- /dev/null +++ b/src/Items/ItemJackOLantern.h @@ -0,0 +1,27 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockPumpkin.h" + + + + + +class cItemJackOLanternHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + // Re-use the pumpkin converter for lanterns: + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_JACK_O_LANTERN, cBlockPumpkinHandler::YawToMetaData(a_Player.GetYaw())); + } +}; diff --git a/src/Items/ItemLadder.h b/src/Items/ItemLadder.h new file mode 100644 index 000000000..67de799c5 --- /dev/null +++ b/src/Items/ItemLadder.h @@ -0,0 +1,77 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockLadder.h" + + + + + +class cItemLadderHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + /** Converts the block face of the neighbor to which the ladder is attached to the ladder block's meta. */ + static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_NeighborBlockFace) + { + switch (a_NeighborBlockFace) + { + case BLOCK_FACE_ZM: return 0x2; + case BLOCK_FACE_ZP: return 0x3; + case BLOCK_FACE_XM: return 0x4; + case BLOCK_FACE_XP: return 0x5; + case BLOCK_FACE_YM: + case BLOCK_FACE_YP: return 0x2; + default: UNREACHABLE("Unsupported neighbor block face"); + } + } + + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + const auto & World = *a_Player.GetWorld(); + const auto ClickedBlockType = World.GetBlock(AddFaceDirection(a_PlacePosition, a_ClickedBlockFace, true)); + + // Try finding a suitable neighbor block face for the ladder; start with the given one: + if (!cBlockLadderHandler::CanBePlacedOn(ClickedBlockType, a_ClickedBlockFace)) + { + // Couldn't be placed on whatever face was clicked, last ditch resort - find another face: + a_ClickedBlockFace = FindSuitableFace(World, a_PlacePosition); + if (a_ClickedBlockFace == BLOCK_FACE_NONE) + { + // No attachable face found - don't place the ladder: + return false; + } + } + + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_LADDER, BlockFaceToMetaData(a_ClickedBlockFace)); + } + + + /** Returns a suitable neighbor's blockface to place the ladder at the specified position. + Returns BLOCK_FACE_NONE on failure. */ + static eBlockFace FindSuitableFace(const cWorld & a_World, const Vector3i a_Position) + { + for (const auto Face : { BLOCK_FACE_ZM, BLOCK_FACE_XP, BLOCK_FACE_ZP, BLOCK_FACE_XM }) // Loop through all faces in specific order. + { + // The direction of Face is relative to the direction the ladder faces. + // This is the position, computed inverted, that such a ladder would attach to. + const auto NeighborPosition = AddFaceDirection(a_Position, Face, true); + + if (cBlockLadderHandler::CanBePlacedOn(a_World.GetBlock(NeighborPosition), Face)) + { + return Face; + } + } + + return BLOCK_FACE_NONE; + } +}; diff --git a/src/Items/ItemLeaves.h b/src/Items/ItemLeaves.h index 0233ed6a6..abe2a76cf 100644 --- a/src/Items/ItemLeaves.h +++ b/src/Items/ItemLeaves.h @@ -23,23 +23,13 @@ public: - virtual bool GetPlacementBlockTypeMeta( - cWorld * a_World, cPlayer * a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) override + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { - bool res = Super::GetPlacementBlockTypeMeta( - a_World, a_Player, - a_PlacedBlockPos, - a_ClickedBlockFace, - a_CursorPos, - a_BlockType, a_BlockMeta + return a_Player.PlaceBlock( + a_PlacePosition, + static_cast(m_ItemType), + static_cast(a_HeldItem.m_ItemDamage | 0x4) // 0x4 bit set means this is a player-placed leaves block, not to be decayed. ); - a_BlockMeta = a_BlockMeta | 0x4; // 0x4 bit set means this is a player-placed leaves block, not to be decayed - return res; } } ; diff --git a/src/Items/ItemLever.h b/src/Items/ItemLever.h new file mode 100644 index 000000000..66c83f485 --- /dev/null +++ b/src/Items/ItemLever.h @@ -0,0 +1,43 @@ + +#pragma once + +#include "ItemHandler.h" + + + + + +class cItemLeverHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + /** Converts the block face of the neighbor to which the lever is attached to the lever block's meta. */ + static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace) + { + // Determine lever direction: + switch (a_BlockFace) + { + case BLOCK_FACE_YP: return 0x6; + case BLOCK_FACE_XP: return 0x1; + case BLOCK_FACE_XM: return 0x2; + case BLOCK_FACE_ZP: return 0x3; + case BLOCK_FACE_ZM: return 0x4; + case BLOCK_FACE_YM: return 0x0; + case BLOCK_FACE_NONE: break; + } + UNREACHABLE("Unsupported block face"); + } + + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + return a_Player.PlaceBlock(a_PlacePosition, static_cast(a_HeldItem.m_ItemType), BlockFaceToMetaData(a_ClickedBlockFace)); + } +}; diff --git a/src/Items/ItemMobHead.h b/src/Items/ItemMobHead.h index 90d67b02b..3d6f1d7aa 100644 --- a/src/Items/ItemMobHead.h +++ b/src/Items/ItemMobHead.h @@ -25,38 +25,30 @@ public: - virtual bool OnPlayerPlace( - cWorld & a_World, - cPlayer & a_Player, - const cItem & a_EquippedItem, - const Vector3i a_ClickedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos - ) override + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { // Cannot place a head at "no face" and from the bottom: if ((a_ClickedBlockFace == BLOCK_FACE_NONE) || (a_ClickedBlockFace == BLOCK_FACE_BOTTOM)) { - return true; + return false; } - const auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); // If the placed head is a wither, try to spawn the wither first: - if (a_EquippedItem.m_ItemDamage == E_META_HEAD_WITHER) + if (a_HeldItem.m_ItemDamage == E_META_HEAD_WITHER) { - if (TrySpawnWitherAround(a_World, a_Player, PlacePos)) + if (TrySpawnWitherAround(a_Player, a_PlacePosition)) { return true; } // Wither not created, proceed with regular head placement } - cItem ItemCopy(a_EquippedItem); // Make a copy in case this is the player's last head item and OnPlayerPlace removes it - if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos)) + if (!a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_HEAD, BlockFaceToBlockMeta(a_ClickedBlockFace))) { return false; } - RegularHeadPlaced(a_World, a_Player, ItemCopy, PlacePos, a_ClickedBlockFace); + + RegularHeadPlaced(a_Player, a_HeldItem, a_PlacePosition, a_ClickedBlockFace); return true; } @@ -66,16 +58,13 @@ public: /** Called after placing a regular head block with no mob spawning. Adjusts the mob head entity based on the equipped item's data. */ - void RegularHeadPlaced( - cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, - const Vector3i a_PlacePos, eBlockFace a_ClickedBlockFace - ) + void RegularHeadPlaced(const cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace) { - auto HeadType = static_cast(a_EquippedItem.m_ItemDamage); - auto BlockMeta = static_cast(a_ClickedBlockFace); + const auto HeadType = static_cast(a_HeldItem.m_ItemDamage); + const auto BlockMeta = static_cast(a_ClickedBlockFace); // Use a callback to set the properties of the mob head block entity: - a_World.DoWithBlockEntityAt(a_PlacePos, [&](cBlockEntity & a_BlockEntity) + a_Player.GetWorld()->DoWithBlockEntityAt(a_PlacePosition, [&a_Player, HeadType, BlockMeta](cBlockEntity & a_BlockEntity) { ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_HEAD); @@ -99,10 +88,7 @@ public: /** Spawns a wither if the wither skull placed at the specified coords completes wither's spawning formula. Returns true if the wither was created. */ - bool TrySpawnWitherAround( - cWorld & a_World, cPlayer & a_Player, - const Vector3i a_BlockPos - ) + bool TrySpawnWitherAround(cPlayer & a_Player, const Vector3i a_BlockPos) { // No wither can be created at Y < 2 - not enough space for the formula: if (a_BlockPos.y < 2) @@ -119,10 +105,11 @@ public: { 0, 0, 1}, { 0, 0, -1}, }; + for (auto & RelCoord : RelCoords) { if (TrySpawnWitherAt( - a_World, a_Player, + *a_Player.GetWorld(), a_Player, a_BlockPos, RelCoord.x, RelCoord.z )) @@ -177,12 +164,12 @@ public: // Try to spawn the wither from each image: return ( TrySpawnWitherFromImage( - a_World, a_Player, ImageWitherX, ARRAYCOUNT(ImageWitherX), + a_World, a_Player, ImageWitherX, a_PlacedHeadPos, a_OffsetX, a_OffsetZ ) || TrySpawnWitherFromImage( - a_World, a_Player, ImageWitherZ, ARRAYCOUNT(ImageWitherZ), + a_World, a_Player, ImageWitherZ, a_PlacedHeadPos, a_OffsetX, a_OffsetZ ) @@ -199,35 +186,39 @@ public: Offset is used to shift the image around the X and Z axis. Returns true iff the wither was created successfully. */ bool TrySpawnWitherFromImage( - cWorld & a_World, cPlayer & a_Player, const sSetBlock * a_Image, size_t a_ImageCount, + cWorld & a_World, cPlayer & a_Player, const sSetBlock (& a_Image)[9], Vector3i a_PlacedHeadPos, int a_OffsetX, int a_OffsetZ ) { - // Check each block individually; simultaneously build the SetBlockVector for clearing the blocks: - sSetBlockVector AirBlocks; - AirBlocks.reserve(a_ImageCount); - for (size_t i = 0; i < a_ImageCount; i++) - { - // Get the absolute coords of the image: - int BlockX = a_PlacedHeadPos.x + a_OffsetX + a_Image[i].GetX(); - int BlockY = a_PlacedHeadPos.y + a_Image[i].GetY(); - int BlockZ = a_PlacedHeadPos.z + a_OffsetZ + a_Image[i].GetZ(); + std::array PositionsToClear; - // If the query is for the placed head, short-circuit-evaluate it: - if ((BlockX == a_PlacedHeadPos.x) && (BlockY == a_PlacedHeadPos.y) && (BlockZ == a_PlacedHeadPos.z)) + // Check each block individually: + for (size_t i = 0; i != std::size(a_Image); i++) + { + // The absolute coords of the block in the image to check. + const Vector3i Block( + a_PlacedHeadPos.x + a_OffsetX + a_Image[i].GetX(), + a_PlacedHeadPos.y + a_Image[i].GetY(), + a_PlacedHeadPos.z + a_OffsetZ + a_Image[i].GetZ() + ); + + // If the query is for the head the player is about to place (remember, it hasn't been set into the world yet), short-circuit-evaluate it: + if (Block == a_PlacedHeadPos) { if (a_Image[i].m_BlockType != E_BLOCK_HEAD) { - return false; // Didn't match + return false; // Didn't match. } - continue; // Matched, continue checking the rest of the image + + PositionsToClear[i] = Block; + continue; // Matched, continue checking the rest of the image. } // Query the world block: BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - if (!a_World.GetBlockTypeMeta({ BlockX, BlockY, BlockZ }, BlockType, BlockMeta)) + if (!a_World.GetBlockTypeMeta(Block, BlockType, BlockMeta)) { // Cannot query block, assume unloaded chunk, fail to spawn the wither return false; @@ -242,7 +233,7 @@ public: // If it is a mob head, check it's a wither skull using the block entity: if ( (BlockType == E_BLOCK_HEAD) && - !a_World.DoWithBlockEntityAt({ BlockX, BlockY, BlockZ }, [&](cBlockEntity & a_BlockEntity) + !a_World.DoWithBlockEntityAt(Block, [&](cBlockEntity & a_BlockEntity) { ASSERT(a_BlockEntity.GetBlockType() == E_BLOCK_HEAD); @@ -253,12 +244,25 @@ public: return false; } - // Matched, continue checking - AirBlocks.emplace_back(BlockX, BlockY, BlockZ, E_BLOCK_AIR, 0); + // Matched, continue checking: + PositionsToClear[i] = Block; } // for i - a_Image // All image blocks matched, try replace the image with air blocks: - if (!a_Player.PlaceBlocks(AirBlocks)) + if ( + !a_Player.PlaceBlocks( + { + { PositionsToClear[0], E_BLOCK_AIR, 0 }, + { PositionsToClear[1], E_BLOCK_AIR, 0 }, + { PositionsToClear[2], E_BLOCK_AIR, 0 }, + { PositionsToClear[3], E_BLOCK_AIR, 0 }, + { PositionsToClear[4], E_BLOCK_AIR, 0 }, + { PositionsToClear[5], E_BLOCK_AIR, 0 }, + { PositionsToClear[6], E_BLOCK_AIR, 0 }, + { PositionsToClear[7], E_BLOCK_AIR, 0 }, + { PositionsToClear[8], E_BLOCK_AIR, 0 }, + }) + ) { return false; } @@ -323,23 +327,6 @@ public: { return true; } - - - - - - virtual bool GetPlacementBlockTypeMeta( - cWorld * a_World, cPlayer * a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) override - { - a_BlockType = E_BLOCK_HEAD; - a_BlockMeta = BlockFaceToBlockMeta(a_ClickedBlockFace); - return true; - } } ; diff --git a/src/Items/ItemNetherWart.h b/src/Items/ItemNetherWart.h index 462ea61f9..61043226d 100644 --- a/src/Items/ItemNetherWart.h +++ b/src/Items/ItemNetherWart.h @@ -24,37 +24,23 @@ public: - virtual bool IsPlaceable(void) override + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { - return true; + // Only allow planting nether wart onto the top side of the block: + if (a_ClickedBlockFace != BLOCK_FACE_TOP) + { + return true; + } + + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_NETHER_WART, 0); } - virtual bool GetPlacementBlockTypeMeta( - cWorld * a_World, cPlayer * a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) override + virtual bool IsPlaceable(void) override { - // Only allow planting nether wart onto the top side of the block: - if (a_ClickedBlockFace != BLOCK_FACE_TOP) - { - return false; - } - - // Only allow placement on soulsand - if ((a_PlacedBlockPos.y < 1) || (a_World->GetBlock(a_PlacedBlockPos.addedY(-1)) != E_BLOCK_SOULSAND)) - { - return false; - } - - a_BlockMeta = 0; - a_BlockType = E_BLOCK_NETHER_WART; return true; } } ; diff --git a/src/Items/ItemObserver.h b/src/Items/ItemObserver.h new file mode 100644 index 000000000..b95882ae0 --- /dev/null +++ b/src/Items/ItemObserver.h @@ -0,0 +1,26 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockObserver.h" + + + + + +class cItemObserverHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_OBSERVER, cBlockObserverHandler::PitchYawToMetaData(a_Player.GetYaw(), a_Player.GetPitch())); + } +}; diff --git a/src/Items/ItemPiston.h b/src/Items/ItemPiston.h new file mode 100644 index 000000000..659300924 --- /dev/null +++ b/src/Items/ItemPiston.h @@ -0,0 +1,26 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockPiston.h" + + + + + +class cItemPistonHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + return a_Player.PlaceBlock(a_PlacePosition, static_cast(a_HeldItem.m_ItemType), cBlockPistonHandler::PitchYawToMetaData(a_Player.GetYaw(), a_Player.GetPitch())); + } +}; diff --git a/src/Items/ItemPlanks.h b/src/Items/ItemPlanks.h new file mode 100644 index 000000000..537e44460 --- /dev/null +++ b/src/Items/ItemPlanks.h @@ -0,0 +1,25 @@ + +#pragma once + +#include "ItemHandler.h" + + + + + +class cItemPlanksHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + return a_Player.PlaceBlock(a_PlacePosition, static_cast(a_HeldItem.m_ItemType), static_cast(a_HeldItem.m_ItemDamage)); + } +}; diff --git a/src/Items/ItemPumpkin.h b/src/Items/ItemPumpkin.h index 897cba279..cd17472b5 100644 --- a/src/Items/ItemPumpkin.h +++ b/src/Items/ItemPumpkin.h @@ -2,6 +2,7 @@ #pragma once #include "ItemHandler.h" +#include "Blocks/BlockPumpkin.h" @@ -14,35 +15,22 @@ class cItemPumpkinHandler: public: - cItemPumpkinHandler(): - Super(E_BLOCK_PUMPKIN) - { - } - - - + using Super::Super; +private: - virtual bool OnPlayerPlace( - cWorld & a_World, - cPlayer & a_Player, - const cItem & a_EquippedItem, - const Vector3i a_ClickedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos - ) override + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { // First try spawning a snow golem or an iron golem: - auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); - if (TrySpawnGolem(a_World, a_Player, PlacePos)) + if (TrySpawnGolem(a_Player, a_PlacePosition)) { // The client thinks that they placed the pumpkin, let them know it's been replaced: - a_Player.SendBlocksAround(PlacePos.x, PlacePos.y, PlacePos.z); + a_Player.SendBlocksAround(a_PlacePosition.x, a_PlacePosition.y, a_PlacePosition.z); return true; } // No golem at these coords, place the block normally: - return Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos); + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_PUMPKIN, cBlockPumpkinHandler::YawToMetaData(a_Player.GetYaw())); } @@ -51,22 +39,24 @@ public: /** Spawns a snow / iron golem if the shape matches the recipe, supposing that the block placed at the specified coords is a pumpkin. Returns true if the golem blocks are removed (for spawning), false if the recipe is not matched. */ - bool TrySpawnGolem(cWorld & a_World, cPlayer & a_Player, const Vector3i a_PumpkinPos) + bool TrySpawnGolem(cPlayer & a_Player, const Vector3i a_PumpkinPos) { - // A golem can't form with a pumpkin below level 2 or above level 255 + // A golem can't form with a pumpkin below level 2 or above level 255: if ((a_PumpkinPos.y < 2) || (a_PumpkinPos.y >= cChunkDef::Height)) { return false; } + auto & World = *a_Player.GetWorld(); + // Decide which golem to try spawning based on the block below the placed pumpkin: - switch (a_World.GetBlock(a_PumpkinPos.addedY(-1))) + switch (World.GetBlock(a_PumpkinPos.addedY(-1))) { - case E_BLOCK_SNOW_BLOCK: return TrySpawnSnowGolem(a_World, a_Player, a_PumpkinPos); - case E_BLOCK_IRON_BLOCK: return TrySpawnIronGolem(a_World, a_Player, a_PumpkinPos); + case E_BLOCK_SNOW_BLOCK: return TrySpawnSnowGolem(World, a_Player, a_PumpkinPos); + case E_BLOCK_IRON_BLOCK: return TrySpawnIronGolem(World, a_Player, a_PumpkinPos); default: { - // No golem here + // No golem here: return false; } } @@ -91,11 +81,14 @@ public: } // Try to place air blocks where the original recipe blocks were: - sSetBlockVector AirBlocks; - AirBlocks.emplace_back(a_PumpkinPos, E_BLOCK_AIR, 0); // Head - AirBlocks.emplace_back(a_PumpkinPos.addedY(-1), E_BLOCK_AIR, 0); // Torso - AirBlocks.emplace_back(a_PumpkinPos.addedY(-2), E_BLOCK_AIR, 0); // Legs - if (!a_Player.PlaceBlocks(AirBlocks)) + if ( + !a_Player.PlaceBlocks( + { + { a_PumpkinPos, E_BLOCK_AIR, 0 }, // Head + { a_PumpkinPos.addedY(-1), E_BLOCK_AIR, 0 }, // Torso + { a_PumpkinPos.addedY(-2), E_BLOCK_AIR, 0 } // Legs + }) + ) { return false; } @@ -143,13 +136,16 @@ public: } // Try to place air blocks where the original recipe blocks were: - sSetBlockVector AirBlocks; - AirBlocks.emplace_back(a_PumpkinPos, E_BLOCK_AIR, 0); // Head - AirBlocks.emplace_back(BodyPos, E_BLOCK_AIR, 0); // Torso - AirBlocks.emplace_back(BodyPos.addedY(-1), E_BLOCK_AIR, 0); // Legs - AirBlocks.emplace_back(BodyPos + ArmOffsets[i], E_BLOCK_AIR, 0); // Arm - AirBlocks.emplace_back(BodyPos - ArmOffsets[i], E_BLOCK_AIR, 0); // Arm - if (!a_Player.PlaceBlocks(AirBlocks)) + if ( + !a_Player.PlaceBlocks( + { + { a_PumpkinPos, E_BLOCK_AIR, 0 }, // Head + { BodyPos, E_BLOCK_AIR, 0 }, // Torso + { BodyPos.addedY(-1), E_BLOCK_AIR, 0 }, // Legs + { BodyPos + ArmOffsets[i], E_BLOCK_AIR, 0 }, // Arm + { BodyPos - ArmOffsets[i], E_BLOCK_AIR, 0 } // Arm + }) + ) { return false; } diff --git a/src/Items/ItemQuartz.h b/src/Items/ItemQuartz.h new file mode 100644 index 000000000..a3aaa49e7 --- /dev/null +++ b/src/Items/ItemQuartz.h @@ -0,0 +1,60 @@ + +#pragma once + +#include "ItemHandler.h" + + + + + +class cItemQuartzHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + /** Converts the block face of the pillar block's "base" to the block's metadata. */ + static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace) + { + switch (a_BlockFace) + { + case BLOCK_FACE_YM: + case BLOCK_FACE_YP: + { + return E_META_QUARTZ_PILLAR; // Top or bottom. + } + + case BLOCK_FACE_ZP: + case BLOCK_FACE_ZM: + { + return 0x4; // North or south. + } + + case BLOCK_FACE_XP: + case BLOCK_FACE_XM: + { + return 0x3; // East or west. + } + default: UNREACHABLE("Unsupported block face"); + } + } + + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + const auto Meta = static_cast(a_Player.GetEquippedItem().m_ItemDamage); + + // Pillar block needs additional direction in the metadata: + if (Meta == E_META_QUARTZ_PILLAR) + { + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_QUARTZ_BLOCK, BlockFaceToMetaData(a_ClickedBlockFace)); + } + + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_QUARTZ_BLOCK, Meta); + } +}; diff --git a/src/Items/ItemRail.h b/src/Items/ItemRail.h new file mode 100644 index 000000000..a259a2a6d --- /dev/null +++ b/src/Items/ItemRail.h @@ -0,0 +1,28 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockRail.h" + + + + + +class cItemRailHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + cChunkInterface ChunkInterface(a_Player.GetWorld()->GetChunkMap()); + const auto RailType = static_cast(a_HeldItem.m_ItemType); + return a_Player.PlaceBlock(a_PlacePosition, RailType, cBlockRailHandler::FindMeta(ChunkInterface, a_PlacePosition, RailType)); + } +}; diff --git a/src/Items/ItemRedstoneDust.h b/src/Items/ItemRedstoneDust.h index 559be843d..d1bb6556c 100644 --- a/src/Items/ItemRedstoneDust.h +++ b/src/Items/ItemRedstoneDust.h @@ -23,69 +23,19 @@ public: - virtual bool IsPlaceable(void) override + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { - return true; + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_REDSTONE_WIRE, 0); } - virtual bool GetPlacementBlockTypeMeta( - cWorld * a_World, cPlayer * a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) override + virtual bool IsPlaceable(void) override { - // Check the block below, if it supports dust on top of it: - auto UnderPos = a_PlacedBlockPos.addedY(-1); - if (UnderPos.y < 0) - { - return false; - } - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - if (!a_World->GetBlockTypeMeta(UnderPos, BlockType, BlockMeta)) - { - return false; - } - if (!IsBlockTypeUnderSuitable(BlockType, BlockMeta)) - { - return false; - } - - a_BlockType = E_BLOCK_REDSTONE_WIRE; - a_BlockMeta = 0; return true; } - - - - - - /** Returns true if the specified block type / meta is suitable to have redstone dust on top of it. */ - static bool IsBlockTypeUnderSuitable(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) - { - if (cBlockInfo::FullyOccupiesVoxel(a_BlockType)) - { - return true; - } - - switch (a_BlockType) - { - case E_BLOCK_RED_SANDSTONE_SLAB: - case E_BLOCK_WOODEN_SLAB: - case E_BLOCK_STONE_SLAB: - { - // Slabs can support redstone if they're upside down: - return ((a_BlockMeta & 0x08) != 0); - } - } - return false; - } } ; diff --git a/src/Items/ItemRedstoneRepeater.h b/src/Items/ItemRedstoneRepeater.h index 6b1635609..6461d3ffd 100644 --- a/src/Items/ItemRedstoneRepeater.h +++ b/src/Items/ItemRedstoneRepeater.h @@ -24,25 +24,17 @@ public: - virtual bool IsPlaceable() override + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { - return true; + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_REDSTONE_REPEATER_OFF, cBlockRedstoneRepeaterHandler::YawToMetaData(a_Player.GetYaw())); } - virtual bool GetPlacementBlockTypeMeta( - cWorld * a_World, cPlayer * a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) override + virtual bool IsPlaceable() override { - a_BlockType = E_BLOCK_REDSTONE_REPEATER_OFF; - a_BlockMeta = cBlockRedstoneRepeaterHandler::YawToMetaData(a_Player->GetYaw()); return true; } } ; diff --git a/src/Items/ItemSapling.h b/src/Items/ItemSapling.h index 513f542f6..3f62af94f 100644 --- a/src/Items/ItemSapling.h +++ b/src/Items/ItemSapling.h @@ -20,30 +20,12 @@ public: } - - - - virtual bool GetPlacementBlockTypeMeta( - cWorld * a_World, cPlayer * a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) override + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { - bool res = Super::GetPlacementBlockTypeMeta( - a_World, a_Player, - a_PlacedBlockPos, a_ClickedBlockFace, - a_CursorPos, - a_BlockType, a_BlockMeta + return a_Player.PlaceBlock( + a_PlacePosition, + static_cast(m_ItemType), + static_cast(a_HeldItem.m_ItemDamage & 0x07) // Allow only the lowest 3 bits (top bit is for growth). ); - - // Allow only the lowest 3 bits (top bit is for growth): - a_BlockMeta = a_BlockMeta & 0x07; - return res; } } ; - - - - diff --git a/src/Items/ItemSeeds.h b/src/Items/ItemSeeds.h index 67d90362a..0bb9afbb9 100644 --- a/src/Items/ItemSeeds.h +++ b/src/Items/ItemSeeds.h @@ -25,47 +25,38 @@ public: - virtual bool IsPlaceable(void) override - { - return true; - } - - - - - - virtual bool GetPlacementBlockTypeMeta( - cWorld * a_World, cPlayer * a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) override + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { // Only allow planting seeds from the top side of the block: - if ((a_ClickedBlockFace != BLOCK_FACE_TOP) || (a_PlacedBlockPos.y <= 0)) + if (a_ClickedBlockFace != BLOCK_FACE_TOP) { return false; } - // Only allow placement on farmland - if (a_World->GetBlock(a_PlacedBlockPos.addedY(-1)) != E_BLOCK_FARMLAND) - { - return false; - } + BLOCKTYPE BlockType; // Get the produce block based on the seed item: - a_BlockMeta = 0; switch (m_ItemType) { - case E_ITEM_BEETROOT_SEEDS: a_BlockType = E_BLOCK_BEETROOTS; return true; - case E_ITEM_CARROT: a_BlockType = E_BLOCK_CARROTS; return true; - case E_ITEM_MELON_SEEDS: a_BlockType = E_BLOCK_MELON_STEM; return true; - case E_ITEM_POTATO: a_BlockType = E_BLOCK_POTATOES; return true; - case E_ITEM_PUMPKIN_SEEDS: a_BlockType = E_BLOCK_PUMPKIN_STEM; return true; - case E_ITEM_SEEDS: a_BlockType = E_BLOCK_CROPS; return true; - default: a_BlockType = E_BLOCK_AIR; return true; + case E_ITEM_BEETROOT_SEEDS: BlockType = E_BLOCK_BEETROOTS; break; + case E_ITEM_CARROT: BlockType = E_BLOCK_CARROTS; break; + case E_ITEM_MELON_SEEDS: BlockType = E_BLOCK_MELON_STEM; break; + case E_ITEM_POTATO: BlockType = E_BLOCK_POTATOES; break; + case E_ITEM_PUMPKIN_SEEDS: BlockType = E_BLOCK_PUMPKIN_STEM; break; + case E_ITEM_SEEDS: BlockType = E_BLOCK_CROPS; break; + default: UNREACHABLE("Unsupported seed type"); } + + return a_Player.PlaceBlock(a_PlacePosition, BlockType, 0); + } + + + + + + virtual bool IsPlaceable(void) override + { + return true; } } ; diff --git a/src/Items/ItemSideways.h b/src/Items/ItemSideways.h new file mode 100644 index 000000000..cb6403fd6 --- /dev/null +++ b/src/Items/ItemSideways.h @@ -0,0 +1,53 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockSideways.h" + + + + + +/** Handler for blocks that have 3 orientations (hay bale, log), specified by the upper 2 bits in meta. +Handles setting the correct orientation on placement. +Additionally supports the metadata specifying block sub-type in its lower 2 bits. */ +class cItemSidewaysHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace, NIBBLETYPE a_Meta) + { + switch (a_BlockFace) + { + case BLOCK_FACE_YM: + case BLOCK_FACE_YP: + { + return a_Meta; // Top or bottom, just return original. + } + case BLOCK_FACE_ZP: + case BLOCK_FACE_ZM: + { + return a_Meta | 0x8; // North or south. + } + case BLOCK_FACE_XP: + case BLOCK_FACE_XM: + { + return a_Meta | 0x4; // East or west. + } + default: UNREACHABLE("Unsupported block face"); + } + } + + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + return a_Player.PlaceBlock(a_PlacePosition, static_cast(a_HeldItem.m_ItemType), BlockFaceToMetaData(a_ClickedBlockFace, static_cast(a_HeldItem.m_ItemDamage))); + } +}; diff --git a/src/Items/ItemSign.h b/src/Items/ItemSign.h index 64d162f8d..fc5174e0b 100644 --- a/src/Items/ItemSign.h +++ b/src/Items/ItemSign.h @@ -3,8 +3,6 @@ #include "ItemHandler.h" #include "../World.h" -#include "../Blocks/BlockSignPost.h" -#include "../Blocks/BlockWallSign.h" #include "../ClientHandle.h" @@ -18,77 +16,68 @@ class cItemSignHandler: public: - cItemSignHandler(int a_ItemType): - Super(a_ItemType) - { - } - + using Super::Super; +private: + /** Converts the block face of the neighbor to which the wallsign is attached to the wallsign block's meta. */ + static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_NeighborBlockFace) + { + switch (a_NeighborBlockFace) + { + case BLOCK_FACE_ZM: return 0x02; + case BLOCK_FACE_ZP: return 0x03; + case BLOCK_FACE_XM: return 0x04; + case BLOCK_FACE_XP: return 0x05; + case BLOCK_FACE_NONE: + case BLOCK_FACE_YP: + case BLOCK_FACE_YM: + { + break; + } + } + return 0x02; + } - virtual bool OnPlayerPlace( - cWorld & a_World, - cPlayer & a_Player, - const cItem & a_EquippedItem, - const Vector3i a_ClickedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos - ) override + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { - // Check if placing on something ignoring build collision to edit the correct sign later on: - BLOCKTYPE ClickedBlockType; - NIBBLETYPE ClickedBlockMeta; - a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta); - cChunkInterface ChunkInterface(a_World.GetChunkMap()); - bool IsReplacingClickedBlock = cBlockHandler::For(ClickedBlockType).DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, a_Player, ClickedBlockMeta); - - // If the regular placement doesn't work, do no further processing: - if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos)) + if (a_ClickedBlockFace == BLOCK_FACE_TOP) + { + if (!a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_SIGN_POST, RotationToMetaData(a_Player.GetYaw()))) + { + return false; + } + } + else if (!a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_WALLSIGN, BlockFaceToMetaData(a_ClickedBlockFace))) { return false; } - // Use IsReplacingClickedBlock to make sure we will edit the right sign: - auto SignPos = IsReplacingClickedBlock ? a_ClickedBlockPos : AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); - // After successfully placing the sign, open the sign editor for the player: - a_Player.GetClientHandle()->SendEditSign(SignPos.x, SignPos.y, SignPos.z); + a_Player.GetClientHandle()->SendEditSign(a_PlacePosition.x, a_PlacePosition.y, a_PlacePosition.z); return true; } - - - virtual bool IsPlaceable(void) override { return true; } - - - - virtual bool GetPlacementBlockTypeMeta( - cWorld * a_World, cPlayer * a_Player, - const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta - ) override + /** Converts the (player) rotation to placed-signpost block meta. */ + static NIBBLETYPE RotationToMetaData(double a_Rotation) { - if (a_ClickedBlockFace == BLOCK_FACE_TOP) + a_Rotation += 180 + (180.f / 16); // So it's not aligned with axis. + if (a_Rotation > 360) { - a_BlockMeta = cBlockSignPostHandler::RotationToMetaData(a_Player->GetYaw()); - a_BlockType = E_BLOCK_SIGN_POST; + a_Rotation -= 360; } - else - { - a_BlockMeta = cBlockWallSignHandler::BlockFaceToMetaData(a_ClickedBlockFace); - a_BlockType = E_BLOCK_WALLSIGN; - } - return true; + + a_Rotation = (a_Rotation / 360) * 16; + + return static_cast(a_Rotation) % 16; } } ; diff --git a/src/Items/ItemSlab.h b/src/Items/ItemSlab.h index 944336f7e..467975047 100644 --- a/src/Items/ItemSlab.h +++ b/src/Items/ItemSlab.h @@ -14,95 +14,87 @@ class cItemSlabHandler: public: - /** Creates a new handler for the specified slab item type. - Sets the handler to use the specified doubleslab block type for combining self into doubleslabs. */ - cItemSlabHandler(int a_ItemType, BLOCKTYPE a_DoubleSlabBlockType): - Super(a_ItemType), - m_DoubleSlabBlockType(a_DoubleSlabBlockType) + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { - } + // Confer BlockSlab.h, which we're in cahoots with to make the below logic work. + + // If clicking a slab, combine it into a double-slab: + if (cBlockSlabHandler::IsAnySlabType(a_Player.GetWorld()->GetBlock(a_PlacePosition))) + { + if (!a_Player.PlaceBlock(a_PlacePosition, GetDoubleSlabType(static_cast(a_HeldItem.m_ItemType)), static_cast(a_HeldItem.m_ItemDamage))) + { + return false; + } + a_Player.SendBlocksAround(a_PlacePosition.x, a_PlacePosition.y, a_PlacePosition.z, 2); // (see below) + return true; + } + + // Set the correct metadata based on player equipped item: + if (!a_Player.PlaceBlock(a_PlacePosition, static_cast(a_HeldItem.m_ItemType), FaceToMetaData(static_cast(a_HeldItem.m_ItemDamage), a_ClickedBlockFace, a_CursorPosition))) + { + return false; + } + /* This is a workaround for versions < 1.13, where the client combines a slab in the + direction of the clicked block face of a block ignoring build collision, rather than replacing said block. + Resend blocks to the client to fix the bug. + Ref.: https://forum.cuberite.org/thread-434-post-17388.html#pid17388 */ + a_Player.SendBlocksAround(a_PlacePosition.x, a_PlacePosition.y, a_PlacePosition.z, 2); + return true; + } - // cItemHandler overrides: - virtual bool OnPlayerPlace( - cWorld & a_World, - cPlayer & a_Player, - const cItem & a_EquippedItem, - const Vector3i a_ClickedBlockPos, - eBlockFace a_ClickedBlockFace, - const Vector3i a_CursorPos - ) override + static NIBBLETYPE FaceToMetaData(const NIBBLETYPE a_BaseMeta, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) { - // If clicking a slab, try combining it into a double-slab: - BLOCKTYPE ClickedBlockType; - NIBBLETYPE ClickedBlockMeta; - a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta); - if ( - (ClickedBlockType == m_ItemType) && // Placing the same slab material - ((ClickedBlockMeta & 0x07) == a_EquippedItem.m_ItemDamage) // Placing the same slab sub-kind (and existing slab is single) - ) + switch (a_ClickedBlockFace) { - if ( - ((a_ClickedBlockFace == BLOCK_FACE_TOP) && ((ClickedBlockMeta & 0x08) == 0)) || // Top side of a bottom-half-slab - ((a_ClickedBlockFace == BLOCK_FACE_BOTTOM) && ((ClickedBlockMeta & 0x08) != 0)) // Bottom side of a top-half-slab - ) + case BLOCK_FACE_TOP: { - if (!a_Player.PlaceBlock(a_ClickedBlockPos.x, a_ClickedBlockPos.y, a_ClickedBlockPos.z, m_DoubleSlabBlockType, ClickedBlockMeta & 0x07)) - { - return false; - } - if (a_Player.IsGameModeSurvival()) - { - a_Player.GetInventory().RemoveOneEquippedItem(); - } - return true; + // Bottom half slab block: + return a_BaseMeta & 0x07; } - } - - // If there's already a slab in the destination, combine it into a double-slab: - auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace); - BLOCKTYPE PlaceBlockType; - NIBBLETYPE PlaceBlockMeta; - a_World.GetBlockTypeMeta(PlacePos, PlaceBlockType, PlaceBlockMeta); - if ( - (PlaceBlockType == m_ItemType) && // Placing the same slab material - ((PlaceBlockMeta & 0x07) == a_EquippedItem.m_ItemDamage) // Placing the same slab sub-kind (and existing slab is single) - ) - { - if (!a_Player.PlaceBlock(PlacePos.x, PlacePos.y, PlacePos.z, m_DoubleSlabBlockType, PlaceBlockMeta & 0x07)) + case BLOCK_FACE_BOTTOM: { - return false; + // Top half slab block: + return a_BaseMeta | 0x08; } - if (a_Player.IsGameModeSurvival()) + case BLOCK_FACE_EAST: + case BLOCK_FACE_NORTH: + case BLOCK_FACE_SOUTH: + case BLOCK_FACE_WEST: { - a_Player.GetInventory().RemoveOneEquippedItem(); + if (a_CursorPosition.y > 7) + { + // Cursor at top half of block, place top slab: + return a_BaseMeta | 0x08; + } + else + { + // Cursor at bottom half of block, place bottom slab: + return a_BaseMeta & 0x07; + } } - return true; + default: UNREACHABLE("Unhandled block face"); } + } - // The slabs didn't combine, use the default handler to place the slab: - bool res = Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos); - /* - The client has a bug when a slab replaces snow and there's a slab above it. - The client then combines the slab above, rather than replacing the snow. - We send the block above the currently placed block back to the client to fix the bug. - Ref.: https://forum.cuberite.org/thread-434-post-17388.html#pid17388 - */ - if ((a_ClickedBlockFace == BLOCK_FACE_TOP) && (a_ClickedBlockPos.y < cChunkDef::Height - 1)) + /** Converts the single-slab blocktype to its equivalent double-slab blocktype. */ + static BLOCKTYPE GetDoubleSlabType(BLOCKTYPE a_SingleSlabBlockType) + { + switch (a_SingleSlabBlockType) { - auto AbovePos = a_ClickedBlockPos.addedY(1); - a_Player.SendBlocksAround(AbovePos.x, AbovePos.y, AbovePos.z, 1); + case E_BLOCK_STONE_SLAB: return E_BLOCK_DOUBLE_STONE_SLAB; + case E_BLOCK_WOODEN_SLAB: return E_BLOCK_DOUBLE_WOODEN_SLAB; + case E_BLOCK_RED_SANDSTONE_SLAB: return E_BLOCK_DOUBLE_RED_SANDSTONE_SLAB; + case E_BLOCK_PURPUR_SLAB: return E_BLOCK_PURPUR_DOUBLE_SLAB; } - return res; + UNREACHABLE("Unhandled slab type"); } - - -protected: - - /** The block type to use when the slab combines into a doubleslab block. */ - BLOCKTYPE m_DoubleSlabBlockType; }; diff --git a/src/Items/ItemSnow.h b/src/Items/ItemSnow.h new file mode 100644 index 000000000..551b4d922 --- /dev/null +++ b/src/Items/ItemSnow.h @@ -0,0 +1,41 @@ + +#pragma once + +#include "ItemHandler.h" + + + + + +class cItemSnowHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + BLOCKTYPE Block; + NIBBLETYPE Meta; + a_Player.GetWorld()->GetBlockTypeMeta(a_PlacePosition, Block, Meta); + + // Check if incrementing existing snow height: + if (Block == E_BLOCK_SNOW) + { + ASSERT(Meta < 7); // BlockSnow.h ensures that if we replace a snow layer, it won't be at max height. + Meta++; + } + else + { + // First time placement: + Meta = 0; + } + + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_SNOW, Meta); + } +}; diff --git a/src/Items/ItemStairs.h b/src/Items/ItemStairs.h new file mode 100644 index 000000000..6fe447be5 --- /dev/null +++ b/src/Items/ItemStairs.h @@ -0,0 +1,47 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockStairs.h" + + + + + +class cItemStairsHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + NIBBLETYPE Meta = cBlockStairsHandler::YawToMetaData(a_Player.GetYaw()); + + switch (a_ClickedBlockFace) + { + case BLOCK_FACE_TOP: break; + case BLOCK_FACE_BOTTOM: Meta |= 0x4; break; // When placing onto a bottom face, always place an upside-down stairs block. + case BLOCK_FACE_EAST: + case BLOCK_FACE_NORTH: + case BLOCK_FACE_SOUTH: + case BLOCK_FACE_WEST: + { + // When placing onto a sideways face, check cursor, if in top half, make it an upside-down stairs block: + if (a_CursorPosition.y > 8) + { + Meta |= 0x4; + } + break; + } + default: UNREACHABLE("Unhandled block face"); + } + + return a_Player.PlaceBlock(a_PlacePosition, static_cast(a_HeldItem.m_ItemType), Meta); + } +}; diff --git a/src/Items/ItemTorch.h b/src/Items/ItemTorch.h new file mode 100644 index 000000000..a0ed86e93 --- /dev/null +++ b/src/Items/ItemTorch.h @@ -0,0 +1,82 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockTorch.h" + + + + + +class cItemTorchHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + /** Converts the block face of the neighbor to which the torch is attached, to the torch block's meta. */ + static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace) + { + switch (a_BlockFace) + { + case BLOCK_FACE_TOP: return E_META_TORCH_FLOOR; + case BLOCK_FACE_EAST: return E_META_TORCH_EAST; + case BLOCK_FACE_WEST: return E_META_TORCH_WEST; + case BLOCK_FACE_NORTH: return E_META_TORCH_NORTH; + case BLOCK_FACE_SOUTH: return E_META_TORCH_SOUTH; + default: UNREACHABLE("Unsupported block face"); + } + } + + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + const auto & World = *a_Player.GetWorld(); + BLOCKTYPE ClickedBlockType; + NIBBLETYPE ClickedBlockMeta; + World.GetBlockTypeMeta(AddFaceDirection(a_PlacePosition, a_ClickedBlockFace, true), ClickedBlockType, ClickedBlockMeta); + + // Try finding a suitable neighbor block face for the torch; start with the given one: + if (!cBlockTorchHandler::CanBePlacedOn(ClickedBlockType, ClickedBlockMeta, a_ClickedBlockFace)) + { + // Couldn't be placed on whatever face was clicked, last ditch resort - find another face: + a_ClickedBlockFace = FindSuitableFace(World, a_PlacePosition); + if (a_ClickedBlockFace == BLOCK_FACE_NONE) + { + // No attachable face found - don't place the torch: + return false; + } + } + + return a_Player.PlaceBlock(a_PlacePosition, static_cast(a_HeldItem.m_ItemType), BlockFaceToMetaData(a_ClickedBlockFace)); + } + + + /** Returns a suitable neighbor's blockface to place the torch at the specified position. + Returns BLOCK_FACE_NONE on failure. */ + static eBlockFace FindSuitableFace(const cWorld & a_World, const Vector3i a_Position) + { + for (const auto Face : { BLOCK_FACE_ZM, BLOCK_FACE_XP, BLOCK_FACE_ZP, BLOCK_FACE_XM, BLOCK_FACE_YP }) // Loop through all faces in specific order. + { + // The direction of Face is relative to the direction the torch faces. + // This is the position, computed inverted, that such a torch would attach to. + const auto NeighborPosition = AddFaceDirection(a_Position, Face, true); + + BLOCKTYPE NeighborBlockType; + NIBBLETYPE NeighborBlockMeta; + a_World.GetBlockTypeMeta(NeighborPosition, NeighborBlockType, NeighborBlockMeta); + + if (cBlockTorchHandler::CanBePlacedOn(NeighborBlockType, NeighborBlockMeta, Face)) + { + return Face; + } + } + + return BLOCK_FACE_NONE; + } +}; diff --git a/src/Items/ItemTrapdoor.h b/src/Items/ItemTrapdoor.h new file mode 100644 index 000000000..9cb89b8bf --- /dev/null +++ b/src/Items/ItemTrapdoor.h @@ -0,0 +1,66 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Blocks/BlockTrapdoor.h" + + + + + +class cItemTrapdoorHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace) + { + switch (a_BlockFace) + { + case BLOCK_FACE_ZP: return 0x1; + case BLOCK_FACE_ZM: return 0x0; + case BLOCK_FACE_XP: return 0x3; + case BLOCK_FACE_XM: return 0x2; + default: UNREACHABLE("Unsupported block face"); + } + } + + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + NIBBLETYPE Meta; + + if (a_ClickedBlockFace == BLOCK_FACE_YP) + { + // Trapdoor is placed on top of a block. + // Engage yaw rotation to determine hinge direction: + Meta = cBlockTrapdoorHandler::YawToMetaData(a_Player.GetYaw()); + } + else if (a_ClickedBlockFace == BLOCK_FACE_YM) + { + // Trapdoor is placed on bottom of a block. + // Engage yaw rotation to determine hinge direction, and toggle 'Move up half-block' bit on: + Meta = cBlockTrapdoorHandler::YawToMetaData(a_Player.GetYaw()) | 0x8; + } + else + { + // Placement on block sides; hinge direction is determined by which side was clicked: + Meta = BlockFaceToMetaData(a_ClickedBlockFace); + + if (a_CursorPosition.y > 7) + { + // Trapdoor is placed on a higher half of a vertical block. + // Toggle 'Move up half-block' bit on: + Meta |= 0x8; + } + } + + return a_Player.PlaceBlock(a_PlacePosition, static_cast(a_HeldItem.m_ItemType), Meta); + } +}; diff --git a/src/Items/ItemTripwireHook.h b/src/Items/ItemTripwireHook.h new file mode 100644 index 000000000..005bd5676 --- /dev/null +++ b/src/Items/ItemTripwireHook.h @@ -0,0 +1,43 @@ + +#pragma once + +#include "ItemHandler.h" + + + + + +class cItemTripwireHookHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace) + { + switch (a_BlockFace) + { + case BLOCK_FACE_XM: return 0x1; + case BLOCK_FACE_XP: return 0x3; + case BLOCK_FACE_ZM: return 0x2; + case BLOCK_FACE_ZP: return 0x0; + default: UNREACHABLE("Unsupported block face"); + } + } + + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + if ((a_ClickedBlockFace == BLOCK_FACE_YP) || (a_ClickedBlockFace == BLOCK_FACE_YM)) + { + return false; + } + + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_TRIPWIRE_HOOK, BlockFaceToMetaData(a_ClickedBlockFace)); + } +}; diff --git a/src/Items/ItemVine.h b/src/Items/ItemVine.h new file mode 100644 index 000000000..1a56a23d0 --- /dev/null +++ b/src/Items/ItemVine.h @@ -0,0 +1,44 @@ + +#pragma once + +#include "ItemHandler.h" + + + + + +class cItemVineHandler : + public cItemHandler +{ + using Super = cItemHandler; + +public: + + using Super::Super; + +private: + + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override + { + BLOCKTYPE Block; + NIBBLETYPE Meta; + a_Player.GetWorld()->GetBlockTypeMeta(a_PlacePosition, Block, Meta); + + NIBBLETYPE PlaceMeta; + switch (a_ClickedBlockFace) + { + case BLOCK_FACE_NORTH: PlaceMeta = 0x1; break; + case BLOCK_FACE_SOUTH: PlaceMeta = 0x4; break; + case BLOCK_FACE_WEST: PlaceMeta = 0x8; break; + case BLOCK_FACE_EAST: PlaceMeta = 0x2; break; + default: return false; + } + + if (Block == E_BLOCK_VINES) + { + PlaceMeta |= Meta; + } + + return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_VINES, PlaceMeta); + } +}; diff --git a/src/Items/SimplePlaceableItemHandler.h b/src/Items/SimplePlaceableItemHandler.h index 4400b9d0e..8b61f3198 100644 --- a/src/Items/SimplePlaceableItemHandler.h +++ b/src/Items/SimplePlaceableItemHandler.h @@ -26,14 +26,9 @@ public: } - virtual bool GetPlacementBlockTypeMeta( - cWorld * a_World, cPlayer * a_Player, const Vector3i a_PlacedBlockPos, - eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) override + virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) override { - a_BlockType = m_BlockType; - a_BlockMeta = 0; - return true; + return a_Player.PlaceBlock(a_PlacePosition, m_BlockType, 0); } private: diff --git a/src/World.cpp b/src/World.cpp index 271a295de..10dc909c9 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -1733,7 +1733,7 @@ void cWorld::SetBlockMeta(Vector3i a_BlockPos, NIBBLETYPE a_MetaData) -NIBBLETYPE cWorld::GetBlockSkyLight(Vector3i a_BlockPos) +NIBBLETYPE cWorld::GetBlockSkyLight(Vector3i a_BlockPos) const { return m_ChunkMap.GetBlockSkyLight(a_BlockPos); } @@ -1742,7 +1742,7 @@ NIBBLETYPE cWorld::GetBlockSkyLight(Vector3i a_BlockPos) -NIBBLETYPE cWorld::GetBlockBlockLight(Vector3i a_BlockPos) +NIBBLETYPE cWorld::GetBlockBlockLight(Vector3i a_BlockPos) const { return m_ChunkMap.GetBlockBlockLight(a_BlockPos); } @@ -1751,7 +1751,7 @@ NIBBLETYPE cWorld::GetBlockBlockLight(Vector3i a_BlockPos) -bool cWorld::GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) +bool cWorld::GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const { return m_ChunkMap.GetBlockTypeMeta(a_BlockPos, a_BlockType, a_BlockMeta); } @@ -1760,7 +1760,7 @@ bool cWorld::GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBB -bool cWorld::GetBlockInfo(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight) +bool cWorld::GetBlockInfo(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight) const { return m_ChunkMap.GetBlockInfo(a_BlockPos, a_BlockType, a_Meta, a_SkyLight, a_BlockLight); } @@ -2017,9 +2017,14 @@ UInt32 cWorld::SpawnEnderCrystal(Vector3d a_Pos, bool a_ShowBottom) void cWorld::PlaceBlock(const Vector3i a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta) { + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + GetBlockTypeMeta(a_Position, BlockType, BlockMeta); + SetBlock(a_Position, a_BlockType, a_BlockMeta); cChunkInterface ChunkInterface(GetChunkMap()); + cBlockHandler::For(BlockType).OnBroken(ChunkInterface, *this, a_Position, BlockType, BlockMeta, nullptr); cBlockHandler::For(a_BlockType).OnPlaced(ChunkInterface, *this, a_Position, a_BlockType, a_BlockMeta); } @@ -2081,7 +2086,7 @@ cItems cWorld::PickupsFromBlock(Vector3i a_BlockPos, const cEntity * a_Digger, c -void cWorld::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer & a_Player) +void cWorld::SendBlockTo(int a_X, int a_Y, int a_Z, const cPlayer & a_Player) { m_ChunkMap.SendBlockTo(a_X, a_Y, a_Z, a_Player); } diff --git a/src/World.h b/src/World.h index 958154bf0..1a5ac8498 100644 --- a/src/World.h +++ b/src/World.h @@ -374,22 +374,22 @@ public: /** Returns the sky light value at the specified block position. The sky light is "raw" - not affected by time-of-day. Returns 0 if chunk not valid. */ - NIBBLETYPE GetBlockSkyLight(Vector3i a_BlockPos); + NIBBLETYPE GetBlockSkyLight(Vector3i a_BlockPos) const; /** Returns the block-light value at the specified block position. Returns 0 if chunk not valid. */ - NIBBLETYPE GetBlockBlockLight(Vector3i a_BlockPos); + NIBBLETYPE GetBlockBlockLight(Vector3i a_BlockPos) const; /** Retrieves the block type and meta at the specified coords. Stores the result into a_BlockType and a_BlockMeta. Returns true if successful, false if chunk not present. TODO: Export in ManualBindings_World.cpp. */ - bool GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); + bool GetBlockTypeMeta(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const; /** Queries the whole block specification from the world. Returns true if all block info was retrieved successfully, false if not (invalid chunk / bad position). Exported in ManualBindings_World.cpp. */ - bool GetBlockInfo(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight); + bool GetBlockInfo(Vector3i a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight) const; // TODO: NIBBLETYPE GetBlockActualLight(int a_BlockX, int a_BlockY, int a_BlockZ); @@ -529,7 +529,7 @@ public: // tolua_end /** Replaces the specified block with another, and calls the OnPlaced block handler. - Callers MUST ensure the replaced block was destroyed or can handle replacement correctly. Wakes up the simulators. + The OnBroken block handler is called for the replaced block. Wakes up the simulators. If the chunk for any of the blocks is not loaded, the set operation is ignored silently. */ void PlaceBlock(const Vector3i a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta); @@ -571,7 +571,7 @@ public: /** Sends the block at the specified coords to the player. Used mainly when plugins disable block-placing or block-breaking, to restore the previous block. */ - virtual void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer & a_Player) override; + virtual void SendBlockTo(int a_X, int a_Y, int a_Z, const cPlayer & a_Player) override; /** Set default spawn at the given coordinates. Returns false if the new spawn couldn't be stored in the INI file. */ diff --git a/tests/Generating/Stubs.cpp b/tests/Generating/Stubs.cpp index 9cec9d904..0564d0781 100644 --- a/tests/Generating/Stubs.cpp +++ b/tests/Generating/Stubs.cpp @@ -112,21 +112,6 @@ cBoundingBox cBlockHandler::GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a -bool cBlockHandler::GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - const Vector3i a_BlockPos, - eBlockFace a_BlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta -) const -{ - return true; -} - - - - - void cBlockHandler::OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, const Vector3i a_RelPos) const { } @@ -160,7 +145,7 @@ cItems cBlockHandler::ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem -bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const +bool cBlockHandler::CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const { return true; } @@ -178,18 +163,9 @@ bool cBlockHandler::IsUseable() const -bool cBlockHandler::IsClickedThrough(void) const -{ - return false; -} - - - - - -bool cBlockHandler::DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const +bool cBlockHandler::DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, Vector3i a_Position, NIBBLETYPE a_Meta, eBlockFace a_ClickedBlockFace, bool a_ClickedDirectly) const { - return (m_BlockType == E_BLOCK_AIR); + return m_BlockType == E_BLOCK_AIR; } diff --git a/tests/LuaThreadStress/Stubs.cpp b/tests/LuaThreadStress/Stubs.cpp index 8f374900f..6f37ea5ee 100644 --- a/tests/LuaThreadStress/Stubs.cpp +++ b/tests/LuaThreadStress/Stubs.cpp @@ -112,21 +112,6 @@ cBoundingBox cBlockHandler::GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a -bool cBlockHandler::GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - const Vector3i a_BlockPos, - eBlockFace a_BlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta -) const -{ - return true; -} - - - - - void cBlockHandler::OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, const Vector3i a_RelPos) const { } @@ -160,7 +145,7 @@ cItems cBlockHandler::ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem -bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const +bool cBlockHandler::CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const { return true; } @@ -178,18 +163,9 @@ bool cBlockHandler::IsUseable() const -bool cBlockHandler::IsClickedThrough(void) const -{ - return false; -} - - - - - -bool cBlockHandler::DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const +bool cBlockHandler::DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, Vector3i a_Position, NIBBLETYPE a_Meta, eBlockFace a_ClickedBlockFace, bool a_ClickedDirectly) const { - return (m_BlockType == E_BLOCK_AIR); + return m_BlockType == E_BLOCK_AIR; } diff --git a/tests/SchematicFileSerializer/Stubs.cpp b/tests/SchematicFileSerializer/Stubs.cpp index f52b09bf9..02d7bc6b4 100644 --- a/tests/SchematicFileSerializer/Stubs.cpp +++ b/tests/SchematicFileSerializer/Stubs.cpp @@ -30,21 +30,6 @@ cBoundingBox cBlockHandler::GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a -bool cBlockHandler::GetPlacementBlockTypeMeta( - cChunkInterface & a_ChunkInterface, cPlayer & a_Player, - const Vector3i a_BlockPos, - eBlockFace a_BlockFace, - const Vector3i a_CursorPos, - BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta -) const -{ - return true; -} - - - - - void cBlockHandler::OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, const Vector3i a_RelPos) const { } @@ -78,7 +63,7 @@ cItems cBlockHandler::ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem -bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) const +bool cBlockHandler::CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, const NIBBLETYPE a_Meta) const { return true; } @@ -96,18 +81,9 @@ bool cBlockHandler::IsUseable() const -bool cBlockHandler::IsClickedThrough(void) const -{ - return false; -} - - - - - -bool cBlockHandler::DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) const +bool cBlockHandler::DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, Vector3i a_Position, NIBBLETYPE a_Meta, eBlockFace a_ClickedBlockFace, bool a_ClickedDirectly) const { - return (m_BlockType == E_BLOCK_AIR); + return m_BlockType == E_BLOCK_AIR; } -- cgit v1.2.3